I am trying to select a few words from the textarea and create bootstrap chips.
I am able to create the chips for selected words. I am trying to highlight the selected words with different background colors.
export class SearchComponent implements OnInit { constructor() { } selectedText = []; regexFromMyArray: RegExp; // tslint:disable-next-line:typedef showSelectedText() { let text = ''; if (window.getSelection) { text = window.getSelection().toString(); if (text) { // console.log(this.selectedText.includes(text)); if (this.selectedText.includes(text) === false) { this.selectedText.push(text); this.regexFromMyArray = new RegExp(this.selectedText.join('|'), 'ig'); console.log(this.regexFromMyArray); } } } // console.log(this.selectedText); return this.selectedText; } // tslint:disable-next-line:typedef removeItem(array, item){ for (const i in array){ if (array[i] === item){ array.splice(i, 1); break; } } } // tslint:disable-next-line:typedef deleteChip(el) { // el.style.display = 'none'; document.getElementById(el).style.display = 'none'; this.removeItem(this.selectedText, el); } ngOnInit(): void { } }
I am not sure how to highlight the words in the selectedText
array. I want to highlight all chip words. Like “Contrary”, “Ipsum”, “classical”, “literature”.
Help will be appreciated.
Advertisement
Answer
This answer is based on the link provided by @RobinDijkhof in there comment.
We will set up the css exactly as provided
*, *::before, *::after { box-sizing: border-box; } .container, .backdrop, textarea { width: 460px; height: 180px; } .highlights, textarea { padding: 10px; font: 20px/28px "Open Sans", sans-serif; letter-spacing: 1px; } .container { display: block; margin: 0 auto; transform: translateZ(0); -webkit-text-size-adjust: none; } .backdrop { position: absolute; z-index: 1; border: 2px solid #685972; background-color: #fff; overflow: auto; pointer-events: none; transition: transform 1s; } .highlights { white-space: pre-wrap; word-wrap: break-word; color: transparent; } textarea { display: block; position: absolute; z-index: 2; margin: 0; border: 2px solid #74637f; border-radius: 0; color: #444; background-color: transparent; overflow: auto; resize: none; transition: transform 1s; } mark { border-radius: 3px; color: transparent; background-color: #b1d5e5; } .perspective textarea { transform: perspective(1500px) translateX(155px) rotateY(45deg) scale(1.1); } textarea:focus, button:focus { outline: none; box-shadow: 0 0 0 2px #c6aada; }
Now to the task will be to convert the JQuery code to Angular. We will build a component that can be used like
<app-textarea-highlight [(ngModel)]='txt' [highlightTexts]='highlightTexts' ></app-textarea-highlight>
Where the values are
highlightTexts = ["text", "demo", "div"]; txt = "This demo shows how to highlight bits of text within a textarea. Alright, that's a lie. You can't actually render markup inside a textarea. However, you can fake it by carefully positioning a div behind the textarea and adding your highlight markup there. }
To enable using property binding we will implement ControlValueAccessor
Below is the code
@Component({ selector: "app-textarea-highlight", templateUrl: "./textarea-highlight.component.html", styleUrls: ["./textarea-highlight.component.css"], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextareaHighlightComponent), multi: true } ] }) export class TextareaHighlightComponent implements ControlValueAccessor { constructor() {} @Input() highlightTexts: string[] = []; @ViewChild("backdrop") $backdrop: ElementRef<HTMLDivElement>; @ViewChild("textarea") $textarea: ElementRef<HTMLTextAreaElement>; textValue: string = ""; get highlightedText () { return this.applyHighlights(this.textValue) } applyHighlights(text) { text = text ? text .replace(/n$/g, "nn") : ''; this.highlightTexts.forEach(x => { text = text .replace(new RegExp(x, 'g'), "<mark>$&</mark>"); }) return text; } handleScroll() { var scrollTop = this.$textarea.nativeElement.scrollTop; this.$backdrop.nativeElement.scrollTop = scrollTop; var scrollLeft = this.$textarea.nativeElement.scrollLeft; this.$backdrop.nativeElement.scrollLeft = scrollLeft; } onChanges: ($value: any) => void; onTouched: () => void; writeValue(value: any): void { if (value !== undefined) { this.textValue = value; } } registerOnChange(fn: any): void { this.onChanges = fn; } registerOnTouched(fn: any): void { this.onTouched = fn; } }
The final step is to set the html
<div class="container"> <div #backdrop class="backdrop"> <div class="highlights" [innerHTML]="highlightedText"></div> </div> <textarea [(ngModel)]="textValue" (scroll)="handleScroll()" #textarea ></textarea> </div>