angulargetter-setterproperty-binding

Angular - Two way binding input property to component with getters / setters


I have the following angular components:

ComponentB which has an input property, and componentA which insert componentB in the template file. The code looks as the following:

componentA.ts:

export class ComponentA{
    isOpen: boolean;

    methodA() {
        this.isOpen = false;
        // do some work
    }
}

componentA.html:

<componentB [(open)]="isOpen"></componentB >

ComponentB.ts:

@Component({
    selector: 'componentB',
    templateUrl: 'ComponentB .html',
    encapsulation: ViewEncapsulation.None,
})
export class ComponentB {

    private _open: boolean = false;

    @Input('open') set open(value: boolean) {
        if (open === this._open) {
            return;
        }
        if (open) {
            // doSomething()
        } else {
            // doSomethingElse()
        }
        this._open = open;
    }

    get open() {
        return this._open;
    }
}

The issue is that isOpen property doesn't seems to reflect the current value of open property, although two way binding was specified.

Why does it happens? How can it be fixed?


Solution

  • Two way binding is a special syntax that angular provides to set the value of a component and listen to value changes at the same time.

    For this purpose special syntax (Banana in a box) "[()]" is used. Please find the official angular documentation about this here.

    In a nutshell, you'll have to provide one property with @Input() decorator, and one property with @Output() decorator. The @Output() property will have the word Change appended to it. So if the @Input property name was x then the output property name shall be xChange. And whenever the underlying bound property is changed, using the EventEmitter of the output property, let the parent component listen to the change (hence two way binding implemented).

    In your case your code would update like this

      @Input('open') set open(value: boolean) {
            if (value === this._open) {
                return;
            }
            if (open) {
                // doSomething()
            } else {
                // doSomethingElse()
            }
            this._open = value;
            this.openChange.emit(this._open); //open value set, the updated value is emitted using the output property.
        }
        get open() {
            return this._open;
        }
          @Output('openChange')  //the output property added
          openChange = new EventEmitter<boolean>();

    Please find the Stack Blitz link.