3

I am trying to create a wrapper component for inputs such as a checkbox but I cannot get the parent (inputValue) variable to change, even though it is set as an ngModel.

This is my component definition:

@Component({
selector: 'my-checkbox',
inputs: ['inputValue', 'label'],    
template: `
    <div class="ui checkbox">
      <input type="checkbox" name="example" [(ngModel)]="inputValue" (change)="onChange($event)">
      <label>{{label}}</label>
    </div>`
})

export class CheckboxComponent {    

inputValue: boolean;

onChange(event) {
    this.inputValue = event.currentTarget.checked;
    console.log(this.inputValue);
}}

And I am using it like this in the parent view:

<my-checkbox [inputValue]="valueToUpdate" [label]="'Test Label'"></my-checkbox>

The console does log correctly and I can see that the internal (inputValue) is updating but not the external 'valueToUpdate' (the ngModel two-way binding is not updating correctly).

2 Answers 2

6

You need to define an output for your component and use the EventEmitter class to fire the corresponding event.

@Component({
  selector: 'my-checkbox',
  inputs: ['inputValue', 'label'],    
  outputs: ['inputValueChange']
  template: `
    <div class="ui checkbox">
      <input type="checkbox" name="example" [(ngModel)]="inputValue" (change)="onChange($event)">
      <label>{{label}}</label>
    </div>`
})
export class CheckboxComponent {    

  inputValue: boolean;
  inputValueChange: EventEmitter<any> = new EventEmitter();

  onChange(event) {
    this.inputValue = event.currentTarget.checked;
    console.log(this.inputValue);
    this.inputValueChange.emit(this.inputValue);
  }
}

This way you will be able to use two binding for your sub component:

<my-checkbox [(inputValue)]="valueToUpdate" [label]="'Test Label'">
</my-checkbox>
Sign up to request clarification or add additional context in comments.

4 Comments

Have a look at my answer for some suggested improvements. Feel free to incorporate them into your answer, if you like them.
Good answer, thank you! The documentation really still needs work!
Just to add brevity, the EventEmitter needs to be declared with a type, i.e: inputValueChange: EventEmitter<any> = new EventEmitter(); otherwise Typescript will complain.
Yes, you're right! Without this, you'll have an error during compilation but this doesn't prevent from executing the code ;-) Thanks for the remark! I updated my answer accordingly...
4

Follow @Thierry's answer (i.e., use an output property), but I suggest using the built-in ngModelChange event, rather than having two event bindings. I.e., having [(ngModel)] and (change) results in two event bindings, hence two event handlers run for each click. The built-in ngModelChange event is also a bit nicer/cleaner because $event is already mapped to the value of the checkbox, rather than the DOM click event. So, here are the suggested changes to @Thierry's answer:

<input type="checkbox" name="example" 
  [ngModel]="inputValue" (ngModelChange)="onChange($event)">


onChange(newValue) {
  this.inputValue = newValue;
  console.log(newValue);
  this.inputValueChange.emit(newValue);
}

Plunker

Comments

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.