npm i quill
npm i ngx-quill
npm i quill-emoji
npm i quill-mention
app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 |
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { QuillModule } from 'ngx-quill' import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule, FormsModule, QuillModule.forRoot() ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { } |
app.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
import { Component } from '@angular/core'; import 'quill-mention'; import 'quill-emoji'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ] }) export class AppComponent { htmlText ="<p>Testing</p>" hasFocus = false; subject: string; atValues = [ { id: 1, value: 'Fredrik Sundqvist', link: 'https://google.com' }, { id: 2, value: 'Patrik Sjölin' } ]; hashValues = [ { id: 3, value: 'Fredrik Sundqvist 2' }, { id: 4, value: 'Patrik Sjölin 2' } ] quillConfig={ toolbar: { container: [ ['bold', 'italic', 'underline', 'strike'], ['code-block'], [{ 'header': 1 }, { 'header': 2 }], [{ 'list': 'ordered'}, { 'list': 'bullet' }], [{ 'script': 'sub'}, { 'script': 'super' }], [{ 'indent': '-1'}, { 'indent': '+1' }], [{ 'direction': 'rtl' }], [{ 'size': ['small', false, 'large', 'huge'] }], [{ 'header': [1, 2, 3, 4, 5, 6, false] }], [{ 'font': [] }], [{ 'align': [] }], ['clean'], ['link'], ['link', 'image', 'video'] ], }, mention: { allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/, mentionDenotationChars: ["@", "#"], source: (searchTerm, renderList, mentionChar) => { let values; if (mentionChar === "@") { values = this.atValues; } else { values = this.hashValues; } if (searchTerm.length === 0) { renderList(values, searchTerm); } else { const matches = []; for (var i = 0; i < values.length; i++) if (~values[i].value.toLowerCase().indexOf(searchTerm.toLowerCase())) matches.push(values[i]); renderList(matches, searchTerm); } }, }, "emoji-toolbar": true, "emoji-textarea": false, "emoji-shortname": true, keyboard: { bindings: { enter:{ key:13, handler: (range, context)=>{ console.log("enter"); return true; } } } } } constructor(){} test=(event)=>{ console.log(event.keyCode); } onSelectionChanged = (event) =>{ if(event.oldRange == null){ this.onFocus(); } if(event.range == null){ this.onBlur(); } } onContentChanged = (event) =>{ } onFocus = () =>{ console.log("On Focus"); } onBlur = () =>{ console.log("Blurred"); } } |
app.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<br/> Subject: <input type="text" [(ngModel)]="subject"/> <br/> <br/> <quill-editor [(ngModel)]="htmlText" placeholder="Enter Text" [modules]="quillConfig" (onSelectionChanged)="onSelectionChanged($event)" (onContentChanged)="onContentChanged($event)"></quill-editor> <h2>Preview email will show the following</h2> Subject: {{subject}} <br/> <br/> Body: <div [innerHTML]="htmlText"> </div> |
app.component.css
1 2 3 |
::ng-deep .ql-snow .ql-editor h1 { font-size: 18px; } |
quill/quill-mention.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
.ql-mention-list-container { width: 270px; border: 1px solid #F0F0F0; border-radius: 4px; background-color: #FFFFFF; box-shadow: 0 2px 12px 0 rgba(30, 30, 30, 0.08); } .ql-mention-list { list-style: none; margin: 0; padding: 0; overflow: hidden; } .ql-mention-list-item { cursor: pointer; height: 44px; line-height: 44px; font-size: 16px; padding: 0 20px; vertical-align: middle; } .ql-mention-list-item.selected { background-color: #D3E1EB; text-decoration: none; } .mention { height: 24px; width: 65px; border-radius: 6px; background-color: #D3E1EB; padding: 3px 0; } .mention>span { margin: 0 3px; } |
FULL SOURCE CODE