B Hull
B Hull

Reputation: 3223

NgModel subscribe only triggers when actual textarea is changed in angular2

I have this code below. Basically it is a component with a directive that subscribes to the model of the textarea.

If i type in the textarea, the subscribe triggers and the console log changes, however if the model is changed externally and received from the @Input in the component the subscribe in the textarea doesn't trigger, even though the text in the textarea is updating.

Why does it not trigger whenever the text is changing?

  @Directive({
      selector: 'textarea[mydir]',
      host: {'ngFormControl':'myCtrl'}
  })
  class MyDirective {
    myCtrl: any;
    constructor(){
            this.myCtrl = new Control();
            this.myCtrl.valueChanges.subscribe(
            (data) => {
               console.log('Model change', data);
            });
    }
  }




  // Project card
  @Component({
    selector: 'four',
    providers: [],
    styles: [ require('./four.scss') ],
    directives: [NgFor, MyDirective],
    template: `
        Hello, this is working! <br>
        <textarea mydir [(ngModel)]="pp.status"></textarea>
    `,
  })
  export class Four {
    @Input() pp: Array<any>;
    constructor() {
    }

  }

Upvotes: 4

Views: 4090

Answers (1)

Thierry Templier
Thierry Templier

Reputation: 202276

In fact, it's the correct behavior. As a matter of fact, the NgModel directive triggers when the update custom event (see this line https://github.com/angular/angular/blob/master/modules/angular2/src/common/forms/directives/ng_model.ts#L97 in the source code) when the view is updated:

viewToModelUpdate(newValue: any): void {
  this.viewModel = newValue;
  ObservableWrapper.callEmit(this.update, newValue);
}

You should use a form control to implement such processing:

@Component({
  selector: 'four',
  directives: [MyDirective],
  template: `
    Hello, this is working! <br>
    <textarea mydir [(ngModel)]="pp.status" [ngFormControl]="myCtrl"></textarea>
  `,
})
export class Four {
  @Input() pp;

  constructor() {
    this.myCtrl = new Control();
    this.myCtrl.valueChanges.subscribe(
      (data) => {
        console.log('Model change');
      });
  }
}

See this plunkr: https://plnkr.co/edit/5E4JZhm32bu8rrPV9nEf?p=preview.

Edit

To achieve what you expect, you need to leverage the control associated with the ngModel and subscribe in its valueChanges property. This way, you will be notified both when the value is updated in the model and from the textarea:

@Directive({
  selector: 'textarea[mydir]',
})
class MyDirective {
  constructor(@Optional() public model: NgModel){
    this.model.control.valueChanges.subscribe(data => {
      console.log('value updated - new value = '+data);
    });
  }
}

I updated my plunkr: https://plnkr.co/edit/5E4JZhm32bu8rrPV9nEf?p=preview.

Upvotes: 4

Related Questions