I am creating a small application that displays a list of "People with first names, last names and ages" fields using ngFor. The application has a search field into which you can enter a query, and then this list will be replaced by new objects from the server based on this query.
I created a directive that extracts the letters from the query inside the ngFor line.
For example, if I have a person in the database, his name is David, and I enter "Dav" inside my query, only the entities that link "Dav" will be downloaded from the server to ngFor, and the letters "Dav" will be highlighted , but id is not. If I have David and Devin, both objects will be selected.
The directive works as expected only if I use the artificial setTimeout () to make sure the new list loads before the directive takes effect. Is there any other way to make this work?
DIRECTIVE:
import { Directive, Input, ElementRef } from '@angular/core';
import { SimpleChanges, Renderer2 } from '@angular/core';
@Directive({
selector: '[appQueryHighlight]'
})
export class QueryHighlightDirective {
@Input('appQueryHighlight') query: string;
queryPos: number;
paragraphElement: HTMLParagraphElement;
constructor(private element: ElementRef, private renderer: Renderer2) {
this.paragraphElement = (<HTMLParagraphElement>this.element.nativeElement);
}
ngOnChanges(changes: SimpleChanges){
setTimeout(()=>{
var childCount = this.paragraphElement.childElementCount;
var text: string = "";
if(childCount > 1) {
for(var i = 0; i < childCount; i++) {
text += (<HTMLSpanElement>this.paragraphElement.childNodes[0]).innerHTML;
console.log("SPAN" + (<HTMLSpanElement>this.paragraphElement.childNodes[0]).innerHTML);
this.paragraphElement.removeChild(this.paragraphElement.childNodes[0]);
}
console.log("Text=" + text)
this.paragraphElement.innerHTML = text;
}
console.log('Directive ngOnChanges: query=' + this.query + ", paragraph=" + this.paragraphElement.innerHTML);
this.queryPos = this.paragraphElement.innerHTML.toUpperCase().indexOf(this.query.toUpperCase());
if(this.query!="" && this.queryPos >= 0) {
var span1 = this.renderer.createElement('span');
var text1 = this.renderer.createText(this.paragraphElement.innerHTML.substring(0,this.queryPos));
this.renderer.appendChild(span1, text1);
var span2 = this.renderer.createElement('span');
var text2 = this.renderer.createText(this.paragraphElement.innerHTML.substr(this.queryPos, this.query.length));
this.renderer.setStyle(span2, 'color', "red");
this.renderer.setStyle(span2, 'text-decoration', "underline");
this.renderer.appendChild(span2, text2);
var span3 = this.renderer.createElement('span');
var text3 = this.renderer.createText(this.paragraphElement.innerHTML.substring(this.queryPos + this.query.length));
this.renderer.appendChild(span3, text3);
this.paragraphElement.innerHTML = "";
this.renderer.appendChild(this.paragraphElement, span1);
this.renderer.appendChild(this.paragraphElement, span2);
this.renderer.appendChild(this.paragraphElement, span3);
}
else {
}
}, 15);
}
}
LIST-COMPONENT.TS:
ngOnChanges(changes: SimpleChanges) {
this.debtsService.getFilteredDebts(this.query)
.subscribe(
(data) => {
this.debtsList = data;
this.afterFilteringQuery = this.query;
},
(err) => console.log("Error occured: " + err)
);
}
LIST-COMPONENT.HTML:
<app-person-item
*ngFor="let person of personList;"
[query]="afterFilteringQuery">
</app-person-item>