Search code examples
angularangular2-template2-way-object-databindingangular2-inputs

Angular 2 Data binding not Working for Input Decorator


I'm trying to change the value for a Donut chart based on the Input Decorator. I'm able to initialize the value but cannot change it any further.

I'm using <input type="number" [(ngModel)]="complete"> to 2 way data bind the value. But its not working. I think it's not working because, the template is already called and we're changing the data later.

Is there any solution to this.?

Working code: http://plnkr.co/edit/hYlFp1BX8ebixQMqAtNj?p=preview

Parent component code:

@Component({
  selector: 'my-app',
  providers: [],
  template: `


    <test-component [complete]="complete"></test-component>
    Completed %:<input type="number" [(ngModel)]="complete">

  `,
  directives: [TestComponent]
})
export class App {
  complete:number=40;
  constructor(){

  }
  test(){
    this.complete=60;
  }
}

Solution

  • The complete value changes at the parent component are being received by the @Input() complete at the directive.

    Your chart is the one not updating. You'll have to repaint the whole chart everytime the value changes.

    My suggestion: make complete an Observable<integer> and push a new value everytime the user changes the complete <input>.

    The relevant changes:

    @Component({
        ...
        <test-component [complete]="complete"></test-component>
        Completed %:<input type="number" [(ngModel)]="complete">
    ...
    export class App {
      complete:number=40;
      constructor(){
    

    Becomes:

    @Component({
        ...
        <test-component [complete]="completeObs"></test-component>
        Completed %:<input type="number" [(ngModel)]="complete" 
                                                   (ngModelChange)="completeObs.next($event)">
    ...
    export class App {
      complete:number=40;
      completeObs:Observable<integer> = new BehaviorSubject<integer>(this.complete);
      constructor(){
    

    And you need to change the directive as well:

    export class TestComponent{
      @Input() complete:Observable<integer>;
    
      ngAfterViewInit() {
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
    
        var colors=['green','orange'];
        var labels=['Completed','Pending'];
    
        this.complete.subscribe((complete) => {      // <-- notice it subscribes to the input
          let incomplete:integer = 100 - complete;
    

    See plunker demo here.