Search code examples
angularangular-ngmodelangular2-templateangular2-forms

Angular2 data binding for custom reusable component


I want to have a template consisting of a label and textbox. This template can be reused at different places in my page. to do that i have created a MyTextComponent. I want to know how to i bind different values to the components input.

for example:

MyTextComponent

import {Component, Input} from 'angular2/core';
@Component({
    selector: 'myText',
    template:`<label>{{someLabel}}</label>
                 <input id=myId type="text" [(ngModel)]=bindModelData>
                 `
})
export class MyTextComponent {
    @Input() myId : string;
    @Input() bindModelData: any;
}

MyPageComponent

import {Component} from 'angular2/core';
import {MyTextComponent} from './MyTextComponent.component'

@Component({
    template:`<myText myId="id1" bindModelData="myString1"></myText>
              <myText myId="id2" bindModelData="myString2"></myText>
              `,
    directives:[MyTextComponent]
})
export class MyPageComponent{
    myString1: string;
    myString2: string;
}

How do i bind MyTextComponent input's ngModel to MyPageComponent local variable?

Edit: Tried after adding @Output, but it didnt work :( the interpolation in the MyPageComponent is blank as well as the log is printing undefined. However the interpolation is working for the mytextComponent. Any ideas

import {Component} from 'angular2/core';
import {MyTextComponent} from './myText.component'

@Component({
    template:`<myText myId="id1" [(bindModelData)]="myString1"></myText>
              <myText myId="id2" [(bindModelData)]="myString2"></myText>
              {{myString1}}
              {{myString2}}

              <button (click)="clicked()">Click Me</button>
              `,
    directives:[MyTextComponent],
    selector:'myPage'
})
export class MyPageComponent{
    myString1: string;
    myString2: string;

    clicked(){
        console.log(this.myString1+'--'+this.myString2);
    }
}


import {Component,Input,Output,EventEmitter} from 'angular2/core';
@Component({
    selector: 'myText',
    template:`<label>{{someLabel}}</label>
                 <input id=myId type="text" [ngModel]=bindModelData (ngModelChange)="updateData($event)">
                 modeldata - {{bindModelData}}
                 `
})
export class MyTextComponent {
    @Input() myId : string;
    @Input() bindModelData: any;
    @Output() bindModelDataChanged: any = new EventEmitter();
    updateData(event) {
       console.log('some random text');
      this.bindModelData = event;
      this.bindModelDataChanged.emit(event);
    }
}

Solution

  • Your myText is missing an @Output()

    import {Component, Input, Output} from 'angular2/core';
    @Component({
        selector: 'myText',
        template:`<label>{{someLabel}}</label>
                     <input id=myId type="text" [ngModel]=bindModelData (ngModelChange)="updateData($event)">
                     `
    })
    export class MyTextComponent {
        @Input() myId : string;
        @Input() bindModelData: any;
    
        // note that this must be named as the input name + "Change"
        @Output() bindModelDataChange: any = new EventEmitter();              
    
        updateData(event) {
          this.bindModelData = event;
          this.bindModelDataChange.emit(event);
        }
    }
    

    then you can use it like

    import {Component} from 'angular2/core';
    import {MyTextComponent} from './MyTextComponent.component'
    
    @Component({
        template:`<myText myId="id1" [(bindModelData)]="myString1"></myText>
                  <myText myId="id2" [(bindModelData)]="myString2"></myText>
                  `,
        directives:[MyTextComponent]
    })
    export class MyPageComponent{
        myString1: string;
        myString2: string;
    }
    

    Plunker example