EN VI

Angular - ngOnChange not triggering even after trying all solutions?

2024-03-10 05:00:04
How to Angular - ngOnChange not triggering even after trying all solutions

i am trying to use ngOnChanges in order to update a string(even or odd) after another variable(counter) changes but the value of message stays '' and doesnt update when the counter changes.

export class CounterComponent{
  counter: number = 0;
  message: string = '';

  ngOnChanges(changes: SimpleChanges) {
    if (changes['counter']) {
      this.message = this.counter % 2 === 0 ? 'Even' : 'Odd';
    }
  }

  increment() {
    this.counter++;
  }

  decrement() {
    this.counter--;
  }
}
      <div>
      <p>Counter: {{ counter }}</p>
      <p>Message: {{ message }}</p>
      <button (click)="increment()">Increment</button>
      <button (click)="decrement()">Decrement</button>
      </div>

Thank you for your time.

I have tried **all solutions ** i could find but nothing works, i have tried these : 1.

 @input counter: number = 0;

 ngOnChanges(changes: any) {
    if (changes.counter) {
      this.message = this.counter % 2 === 0 ? 'Even' : 'Odd';
    }
  }

 ngOnChanges(changes: any) {
    if (changes.counter.currentValue) {
      this.message = this.counter % 2 === 0 ? 'Even' : 'Odd';
    }
  }

 ngOnChanges(changes: SimpleChanges) {
    if (changes['counter'].currentValue) {
      this.message = this.counter % 2 === 0 ? 'Even' : 'Odd';
    }
  }

Solution:

There are a few ways to implement this.

In your attempt to add @Input() counter = 0. To trigger ngOnChanges, you need to change the input from the parent component through databinding, which is why you didn't see it get triggered. As you were triggering it locally in the class instead.

The first way would be to switch out OnChanges with DoCheck, as OnChanges only runs when an @Input changes and your counter is not an @Input. So it would look something like this:

@Component({
  selector: 'do-check',
  standalone: true,
  template: `
    <div>
      <p>Counter: {{ counter }}</p>
      <p>Message: {{ message }}</p>
      <button (click)="increment()">Increment</button>
      <button (click)="decrement()">Decrement</button>
    </div>
  `,
})
export class DoCheckExample implements DoCheck {
  counter: number = 0;
  message: string = '';

  ngDoCheck() {
    this.message = this.counter % 2 === 0 ? 'Even' : 'Odd';
  }

  increment() {
    this.counter++;
  }

  decrement() {
    this.counter--;
  }
}

Another way would be to use an rxjs BehaviorSubject to pass the data to the template when the value changes. This approach gives you more control of the flow of data for more advanced components/services/directives. It is also performs a lot less calculations than the previous approach, as that will run every time change detection runs. This only runs when the value is updated, and then a cachelike feature is used otherwise.

@Component({
  selector: 'event',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div *ngIf="counter$ | async as count">
      <p>Counter: {{ count.count }}</p>
      <p>Message: {{ count.msg }}</p>
      <button (click)="counter.next(count.count + 1)">Increment</button>
      <button (click)="counter.next(count.count - 1)">Decrement</button>
    </div>
  `,
})
export class EventExample {
  protected counter = new BehaviorSubject<number>(0);
  counter$ = this.counter.pipe(
    map((i) => ({
      msg: i % 2 === 0 ? 'Even' : 'Odd',
      count: i,
    })),
    tap(() => console.log('Counter Changed!'))
  );
}
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login