0

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?

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

0
private _open= false;

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

get open() {
    return this._open;
}

can you try this ?

btw @Input() open : boolean = false; is a lint mistake. when you assign = false to value it's type will automatically assign as boolean you don't have to specify it

4 Comments

Tnx! but wWhen I access the value of isOpen from componentA (after view init) it's value is still undefined
Why don't you use output? @Output() onValueChange : EventEmitter<boolean> = new EventEmitter(); private _open= false; @Input('open') set open(value: boolean) { if (value=== this._open) { return; } if (value) { // doSomething() } else { // doSomethingElse() } this._open = value; this.onValueChange.emit(value); } get open() { return this._open; } in ComponentA html <componentB [(open)]="isOpen" (onValueChange)="methodHere($event)"></componentB > in ComponentA .ts onValueChange(open: boolean){ }
and also if you want to avoid undefined in child component you should check if input equal undefined in setter. Maybe you're sending undefined as a variable to child component hence it couldn't take it's default variable but takes undefined as variable. @Input('open') set open(value: boolean) { if(value !== undefined){ if (value=== this._open) { return; } if (value) { // doSomething() } else { // doSomethingElse() } this._open = value; } }
for else block you should equal _open to false

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.