Reputation: 1164
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: '='
}
};
});
Upvotes: 8
Views: 8206
Reputation: 23803
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>
Upvotes: 6
Reputation: 202176
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.
Upvotes: 8