Detectar mudança para ngModel em uma tag selecionada (Angular 2)

97

Estou tentando detectar uma alteração ngModelem uma <select>tag. No Angular 1.x, podemos resolver isso com um $watchligado ngModelou usando ngChange, mas ainda não entendi como detectar uma mudança ngModelno Angular 2.

Exemplo completo : http://plnkr.co/edit/9c9oKH1tjDDb67zdKmr9?p=info

import {Component, View, Input, } from 'angular2/core';
import {FORM_DIRECTIVES} from 'angular2/common';

@Component({
    selector: 'my-dropdown'
})
@View({
    directives: [FORM_DIRECTIVES],
    template: `
        <select [ngModel]="selection" (ngModelChange)="onChange($event, selection)" >
            <option *ngFor="#option of options">{{option}}</option>
        </select>
        {{selection}}
    `
})
export class MyDropdown {
    @Input() options;

    selection = 'Dog';

    ngOnInit() {
        console.log('These were the options passed in: ' + this.options);
  }

  onChange(event) {
    if (this.selection === event) return;
    this.selection = event;
    console.log(this.selection);
  }

}

Como podemos ver, se selecionarmos um valor diferente na lista suspensa, nossas ngModelalterações e a expressão interpolada na visualização refletirão isso.

Como posso ser notificado sobre essa mudança em minha classe / controlador?

Luxo
fonte
1
você pode querer manter alguns dos comentários extras sob controle; você não quer que esta pergunta seja sinalizada como um discurso retórico disfarçado. stackoverflow.com/help/dont-ask .
Claies

Respostas:

234

Atualização :

Separe as associações de evento e propriedade:

<select [ngModel]="selectedItem" (ngModelChange)="onChange($event)">
onChange(newValue) {
    console.log(newValue);
    this.selectedItem = newValue;  // don't forget to update the model here
    // ... do other stuff here ...
}

Você também pode usar

<select [(ngModel)]="selectedItem" (ngModelChange)="onChange($event)">

e você não teria que atualizar o modelo no manipulador de eventos, mas acredito que isso faz com que dois eventos sejam disparados, então provavelmente é menos eficiente.


Resposta antiga, antes de consertar um bug na versão beta.1:

Crie uma variável de modelo local e anexe um (change)evento:

<select [(ngModel)]="selectedItem" #item (change)="onChange(item.value)">

plunker

Veja também Como posso obter uma nova seleção em "selecionar" no Angular 2?

Mark Rajcok
fonte
1
Então, de que adianta ngModelse estou apenas vinculando uma nova variável chamada item? Não é o ponto de ngModelcolocar entre parênteses para adquirir ouvintes de evento, então por que estamos introduzindo uma nova variável?
lux
2
@lux, sim, boa pergunta. selectedItemsão os nossos dados vinculados, que o NgModel atualiza automaticamente para nós, mas ... ele não nos notifica sobre mudanças, o que geralmente é bom o suficiente (visualizações e outros serão atualizados), mas obviamente isso não é bom o suficiente para o seu caso de uso. Na outra pergunta do SO que mencionei, descrevo como tentei usar (ngModelChange)para ser notificado sobre as mudanças, mas ele é chamado duas vezes para cada mudança. Não sei se isso é um bug ou não. De qualquer forma, adicionar uma (change)associação de evento parece resolver o problema.
Mark Rajcok
Além disso, atualizei o plunker que mostra que selectedItemnão é atualizado quando onChange()dispara, portanto, parece que precisamos dessa variável de modelo local.
Mark Rajcok
@lux o #ou #itemno nosso caso é uma referência local . Daí porque somos capazes de fazer item.changelá.
Mark Pieszak - Trilon.io
@lux, já descrevi a maneira de conectar: ​​vincular ao ngModelChangeevento personalizado. O problema é que, com <select>esse evento, é disparado duas vezes para cada alteração.
Mark Rajcok
12

Eu tropecei nesta pergunta e vou enviar minha resposta que usei e funcionei muito bem. Eu tinha uma caixa de pesquisa que filtrava uma série de objetos e na minha caixa de pesquisa usei o(ngModelChange)="onChange($event)"

no meu .html

<input type="text" [(ngModel)]="searchText" (ngModelChange)="reSearch(newValue)" placeholder="Search">

então no meu component.ts

reSearch(newValue: string) {
    //this.searchText would equal the new value
    //handle my filtering with the new value
}
Logan H
fonte
5
Apenas FYI, quando vinculado a ngModelChange, $eventnão é um evento DOM . Em vez disso, é o valor atual do elemento do formulário, que é uma string para um elemento de entrada.
Mark Rajcok
@MarkRajcok você pode me indicar a documentação para isso, para que eu possa compartilhar com o resto da minha equipe de desenvolvimento?
Neil S
1
@NeilS, o mais próximo é angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel
Mark Rajcok