matt
matt

Reputation: 749

How to detect change to a property in Angular

I have a component with a sub component timeline.

<app-timeline [(editing)]="editingDate"></app-timeline>

In the timeline component I have these properties:

@Input() editing: boolean; // <--- detect change on this
@Output() editingChange = new EventEmitter();

How can I check when a change to the editing property occurs from the timeline component? I need to emit the editing value whenever it changes.

Should I use a setter for the editing property then emit from there?

private _editing
set editing() { ... // emit }

Or is there another way?

Upvotes: 27

Views: 41458

Answers (3)

NewHorse
NewHorse

Reputation: 13

You could use ngAfterViewChecked callback method and lastEditing flag for testing if editing changed:

import {
  AfterViewChecked,
  Component,
  EventEmitter,
  Input,
  Output,
} from '@angular/core';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html'
})
export class ExampleComponent implements AfterViewChecked {
  @Input() editing: boolean = false;
  lastEditing: boolean = false;
  
  @Output() editingChanged = new EventEmitter<boolean>();

  ngAfterViewChecked(): void {
if (this.editing != this.lastEditing) {
      this.lastEditing = this.editing;
      this.editingChange?.emit(this.editing)
    }
  }
}

This component could be used like this:

<app-timeline [editing]="editingDate" (editingChanged)="eChanged($event)" ></app-timeline>

Upvotes: 0

skdonthi
skdonthi

Reputation: 1442

ngOnChanges looks for every change in the component lifecycle. Using it is kinda overkill.

You don't need two-way binding(again it's up to you and the requirement)

Just use property binding instead...

<app-timeline [editing]="editingDate"></app-timeline>

Whenever editing sets then you have to emit the Output()

@Output() editingChange = new EventEmitter();

public get editing(): boolean {
   return this._editing;
}

@Input()
public set editing(edit: boolean) {
    if (edit) {
        this._editing = edit;
        this.editingChange.emit("something");
    }
}

Upvotes: 9

Jelle
Jelle

Reputation: 2176

The ngOnChanges can be used exactly for this

First make sure your component implements the ngOnChanges like this

export class TimelineComponent implements OnChanges

Then implement the ngOnChanges method like this

ngOnChanges(changes: SimpleChanges) {
    if (changes.editing) {
        console.log(changes.editing.currentValue);
    }
}

Any time any input was changed it will enter the ngOnChanges method. This is also why the if statement was added since if any other input was changed the editing property won't exist on the changes object.

For primitive values it will trigger on any change. For reference values you need to change the actual reference, just changing a property of the object you have in the input won't work.

Upvotes: 29

Related Questions