I have this span
<span *ngFor="let list of lists[0].question; let i = index" id="word{{ i }}" (click)="changestyle($event)" >
{{ list}}
</span>
when i try to get all the element with class highlight
check() {
let highlight_text= $('.highlight');
console.log(highlight_text.length);
for (let i = 0; i < highlight_text.length; i ) {
Getting length 0 but i have class with this name it should return those elements.
Any solution. Thanks
CodePudding user response:
The problem concerns the call of the check
method, it shouldn't be in the ngOnInit
I tried it using ngAfterViewInit
as following:
ngAfterViewInit(): void {
this.check();
}
and I found the length is >0
CodePudding user response:
Answering to @The Fabio's comment below his answer and providing a possible answer to the original question.
Why it's not good to use the function to evaluate a class within [ngClass]
? Or, more generally speaking, why it's a bad idea to use function calls in Angular template expressions?
The problem is caused by the fact that the Angular change detection needs to call the function to see if there was some change => while looping through large lists you'll end up calling the function hundreds of times even when the real change does not affect it. Such function will be executed every time you click on some button, write into a binded input and so on. See the Stackblitz Demo.
When trying to solve the original problem, it's good to have a look on the original list and see what can be done with it. I strongly suggest to use the View Model which provides extended properties to the original Data Model.
// Possible Question View Model
// extending the original one allows to add new properties while keeping the old ones
interface IQuestionVM extends IQuestionDTO {
hasHighlight: boolean
}
//then somewhere in the code, ngOnInit is safe place for this
this.processedQuestions: Array<IQuestionVM> = this.lists[0]question.map(q => ({
...q, // spread the original object
hasHighlight: q.something === 0 // evaluate the condition and assign to extended property
}))
This will allow to simplify and optimize the HTML template:
<span
*ngFor="let list of processedQuestions; let i = index" id="word{{ i }}"
(click)="changestyle($event)"
[ngClass]="{ 'highlight': list.hasHighlight }"
>
{{ list }}
</span>
This approach eliminates the need for a special function to check the class, eliminates the need to look for the elements, and at the same time makes it easier to handle highlight updates. No additional variables, arrays, functions, jQuery are longer necessary.
CodePudding user response:
Mixing angular and jQuery you would be up to a lot of monkey-patching...
If the objective is to set the class on the element based on attributes, the best bet is the ngClass Directive:
<span *ngFor="let list of lists[0].question; let i = index" id="word{{ i }}" (click)="changestyle($event)" [ngClass] = {'highlight': shouldHighlight(list)}>
{{ list}}
</span>
and in the component you create a function
shouldHighlight(list) {
// your condition, returning true or false
}