Can not read property 'setAttribute' of null with ngFor

0

I have a ngFor that adds multiple strings, and that data comes from an api

<p class="teste" *ngFor="let element of objeto_retorno" >Filial {{ element.FILIAL }} = {{ element.TOTAL }} </p>

and no ts:

  ngOnInit() {
    document.querySelector('.teste').setAttribute('class','cor')
  }

But he gets this error: Can not read property 'setAttribute' of null

I think it's because of ngFor, but I can not figure it out, can someone give me a light?

    
asked by anonymous 15.08.2018 / 15:32

2 answers

2

I recommend using Angular, do not need to do things like this manually.

Using querySelector and querySelectorAll for elements that constantly change with Angular is quite unnecessary and still problematic .

Then apply directly (if it is in fact at the time the elements are populated / generated):

<p class="teste" *ngFor="let element of objeto_retorno" >Filial {{ element.FILIAL }} = {{ element.TOTAL }} </p>

Just to note the problem is that even if ngAfterViewInit resolves first, if the data is repopulated the DOM is changed, usually the elements do not even exist yet, even though the screen has been loaded, even if it is imperceptible to you maybe the elements take a few milliseconds to be generated, and so something like that will not work right:

 document.querySelector('.teste').setAttribute('class','cor')

But if you want to apply as an event occurs then do something like:

<p [class]="propriedadeDaClasse ? 'cor': 'teste'" *ngFor="let element of objeto_retorno" >Filial {{ element.FILIAL }} = {{ element.TOTAL }} </p>

This example above would be the equivalent of setAttribute (which changes the class), note that propriedadeDaClasse can be an "if" too, something like:

<p [class]="x != y ? 'cor': 'teste'" *ngFor="let element of objeto_retorno" >Filial {{ element.FILIAL }} = {{ element.TOTAL }} </p>

Both the hypothetical variable propriedadeDaClasse , and x and y must exist in the scope of this of your class, something like, examples:

export class FooBar {
    propriedadeDaClasse = false;
}

Or:

export class FooBar {
    x = 1;
    y = 2;
}

Now if you want to keep the "test" class along with "color" you will have to do this:

<p [class]="propriedadeDaClasse ? 'teste cor': 'teste'" *ngFor="let element of objeto_retorno" >Filial {{ element.FILIAL }} = {{ element.TOTAL }} </p>

So in this way the Angular itself will understand when the DOM is changed and apply the classes as needed.

If they are classes (varied colors) the best would be to apply the color to a variable, something like:

export class FooBar {
    mainColor = ''; //começa sem cor, mas pode trocar '' por algo como 'cor'

     ...
}

Then on:

<p [class]="mainColor + ' teste'" *ngFor="let element of objeto_retorno" >Filial {{ element.FILIAL }} = {{ element.TOTAL }} </p>

So concatenates mainColor + ' teste' both classes, which will generate things like:

class="cor1 teste"

or:

class="cor2 teste"

Inside the class, just change the color at any time, for example:

this.mainColor = 'cor1';

Or:

this.mainColor = 'cor2';

And in css:

.cor1 {
    color: red;
}

.cor2 {
    color: blue;
}

Just examples, you adapt to your need

    
15.08.2018 / 16:38
0

Try to make querySelector for an id.

document.querySelector('#idteste').setAttribute('class','cor');

console.log('document.querySelector(\'#idteste\')', document.querySelector('#idteste'))
console.log('document.querySelector(\'.teste\')', document.querySelector('.teste'))
<p id="idteste" class="teste" *ngFor="let element of objeto_retorno" >

Edit: Plunker

It has to be placed in ngAfterViewInit because at this stage the DOM will be fully loaded.

    
15.08.2018 / 15:43