Search code examples
angularangular-directive

Angular @Input() not updating value is changed in parent component even when using ngOnChanges


I have a little problem and I am not sure what the issue is, perhaps someone here can help?

In my Angular App I have a component that contains a child directive that is attached to form inputs. This child directive takes an @Input() which is a string array called errors.

So in the parent HTML template we have something like so...

<!-- parent-component.component.html file -->
<input type="text" myDirectiveName [errors]="errors">

I want it so that when the errors sting array value changes this change is detected in the directive. I always thought that @Inputs() are treated as Observables so in the parent component I did the following (I have reduced the code for simplicity)

@Component({
  selector: 'parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.scss']
})
export class ParentComponent implements OnInit {
    
    // declare the errors string array
    errors = [];

    ngOnInit(): void {
        this.getErrors();
    }

    getErrors(): void {
        setInterval(() => {
          if(this.errors.length > 3) {
            this.errors.length = 0;
          } else {
            this.errors.push('This is an error');
          }
        }, 1000);
    }
}

I thought this would automatically update in my @Input but it does not, even though if I write the errors array to parent interface in the parent-component.component.html file using {{ errors | json }} I can see the array increase and shrink over time.

So, I thought I will use ngOnChanges within my Directive to capture the changes, here is some simplified code:

@Directive({
  selector: '[myDirectiveName]'
})
export class errorDirective implements OnInit, OnChanges {

@Input() errors: string[];

ngOnInit() {
// do stuff...
}

ngOnChanges(simpleChange: any) {
    console.log(simpleChange);
  }
}

Using this code I can see the changes being output as the Input is initialized but not when I change the value later in the parent. Is the problem how I am changing my errors array using setTimeout? I'm really confused why I can't capture the changes via the Directive Input()? If anyone can help me understand what I am doing wrong I would be most appreciative.

Also if my wording is confusing or wrong please add a comment and I shall reword/rework this question.


Solution

  • Errors is an array, which is an object i.e. immutable. for inputs to detect changes in ngonchanges you have to assign a new reference to array. one of the way is to create shallow copy by using spread operator where ever are are adding or removing any value from array.

    this.errors.push('new error');
    this.errors = [...this.errors];