I have done this in angular 1.x but i want to know how to highlight a dynamic word in angular 2..in angular 1.x iam using a keyword
<td><div highlight="var" keywords="somename"> {{paragraph}}</div></td>
I have done the above html by using the below angular-highlight.js .
angular.module('angular-highlight', [])
.directive('highlight', function()
{
var component = function(scope, element, attrs) {
if (!attrs.highlightClass) {
attrs.highlightClass = 'angular-highlight';
}
var replacer = function(match, item) {
return '<span class="'+attrs.highlightClass+'">'+match+'</span>';
}
var tokenize = function(keywords) {
keywords = keywords.replace(new RegExp(',$','g'), '').split(',');
var i;
var l = keywords.length;
for (i=0;i<l;i++) {
keywords[i] = '\\b'+keywords[i].replace(new RegExp('^ | $','g'), '')+'\\b';
}
return keywords;
}
scope.$watch('keywords', function() {
//console.log("scope.keywords",scope.keywords);
if (!scope.keywords || scope.keywords == '') {
element.html(scope.highlight);
return false;
}
var tokenized = tokenize(scope.keywords);
var regex = new RegExp(tokenized.join('|'), 'gmi');
//console.log("regex",regex);
// Find the words
var html = scope.highlight.replace(regex, replacer);
element.html(html);
});
}
return {
link: component,
replace: false,
scope: {
highlight: '=',
keywords: '='
}
};
});
Things have changed between AngularJS and Angular, but the topic is still very valuable. Being able to manipulate HTML on the fly can solve many problems in Angular. We're going to see how to highlight text within HTML using a query string and simple replace logic.
A very simple and straightforward highlight directive in Angular. We see something similar in chrome dev tools. The idea is pretty simple. We just have to match the searched term and somehow wrap the matched text in a span or mark ( ref) tag so that we can style them later according to our needs.
First it makes sense to come up with some basic CSS for highlighting text. With the very simple CSS out of the way, we can have a look at the logic involved for manipulating the HTML. Open the project's src/app/app.component.ts file and include the following TypeScript code:
The content displayed on the screen is powered by the p tag with the [innerHTML] attribute. The [innerHTML] attribute is very important as it allows us to render HTML from a variable. The data rendered comes from our highlight method. You just saw how to do a few things with Angular.
I would create a custom directive for this:
@Directive({
selector: '[highlight]'
})
export class HighlightDirective {
@Input()
keywords:string;
highlightClass: string = 'highlight';
constructor(private elementRef:ElementRef,private renderer:Renderer) {
}
replacer(match, item) {
return `<span class="${this.highlightClass}">${match}</span>`;
}
tokenize(keywords) {
keywords = keywords.replace(new RegExp(',$','g'), '').split(',');
return keywords.map((keyword) => {
return '\\b'+keyword.replace(new RegExp('^ | $','g'), '')+'\\b';
});
}
ngOnChanges() {
if (this.keywords) {
var tokenized = this.tokenize(this.keywords);
var regex = new RegExp(tokenized.join('|'), 'gmi');
var html = this.elementRef.nativeElement.innerHTML.replace(regex, (match, item) => {
return this.replacer(match, item);
});
this.renderer.setElementProperty(this.elementRef.nativeElement, 'innerHTML', html);
}
}
}
And use it like this:
@Component({
selector: 'app'
template: `
<p highlight keywords="test,angular2">
this is a test to highlight words with angular2
</p>
`,
styles: [`
.highlight {
background-color: yellow;
}
`]
directives: [ HighlightDirective ]
})
export class App {
}
According to the ViewEncapsulation used, you could need an hack (in the emulated one - default on) to add an attribute to be able to see styles applied:
replacer(match, item) {
return `<span ${encapsulationAttribute} class="${this.highlightClass}">${match}</span>`;
}
ngOnChanges() {
this.initializeEncapsulationAttribute();
(...)
}
initializeEncapsulationAttribute() {
if (!this.encapsulationAttribute) {
var attributes = this.elementRef.nativeElement.attributes;
for (var i = 0; i<attributes.length; i++) {
let attr = attributes[i];
if (attr.name.indexOf('_ngcontent') != -1) {
this.encapsulationAttribute = attr.name;
break;
}
}
}
}
See this plunkr: https://plnkr.co/edit/XxB1pFEyUHlZetxtKMUO?p=preview.
In case someone is interested in a simple (generic) solution, I came up with a directive (based on Thierry Templier work !).
This directive allows you to pass the text to work with, the search text and a class to apply :
import { Directive, ElementRef, Renderer, Input, OnInit } from '@angular/core';
import { escapeStringRegexp } from '../helpers/helper';
@Directive({
selector: '[appColorSearchedLetters]'
})
export class ColorSearchedLettersDirective implements OnInit {
@Input() search: string;
@Input() text: string;
@Input() classToApply: string;
constructor(private el: ElementRef, private renderer: Renderer) { }
ngOnInit() {
if (typeof this.classToApply === 'undefined') {
this.classToApply = '';
}
if (typeof this.search === 'undefined') {
this.renderer.setElementProperty(this.el.nativeElement, 'innerHTML', this.text);
return;
}
let search = escapeStringRegexp(this.search.toString());
this.renderer.setElementProperty(this.el.nativeElement, 'innerHTML', this.replace(this.text, search));
}
replace(txt: string, search: string) {
let searchRgx = new RegExp('('+search+')', 'gi');
return txt.replace(searchRgx, `<span class="${this.classToApply}">$1</span>`);
}
}
And the helper
import { escapeStringRegexp } from '../helpers/helper';
contains :
let matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
export function escapeStringRegexp (str) {
if (typeof str !== 'string') {
throw new TypeError('Expected a string');
}
return str.replace(matchOperatorsRe, '\\$&');
};
This function is from https://www.npmjs.com/package/escape-string-regexp and credit goes to Sindresorhus.
Here's how I use it :
<span appColorSearchedLetters [search]="search" [text]="user.name" classToApply="searched"></span>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With