Como posso obter uma nova seleção em "select" no Angular 2?

372

Estou usando o Angular 2 (TypeScript).

Quero fazer algo com a nova seleção, mas o que recebo onChange()é sempre a última seleção. Como posso obter a nova seleção?

<select [(ngModel)]="selectedDevice" (change)="onChange($event)">
   <option *ngFor="#i of devices">{{i}}</option>
</select>
onChange($event) {
    console.log(this.selectedDevice);
    // I want to do something here with the new selectedDevice, but what I
    // get here is always the last selection, not the one I just selected.
}
Hongbo Miao
fonte

Respostas:

750

Se você não precisar de ligação de dados bidirecional:

<select (change)="onChange($event.target.value)">
    <option *ngFor="let i of devices">{{i}}</option>
</select>

onChange(deviceValue) {
    console.log(deviceValue);
}

Para ligação de dados bidirecional, separe as ligações de evento e propriedade:

<select [ngModel]="selectedDevice" (ngModelChange)="onChange($event)" name="sel2">
    <option [value]="i" *ngFor="let i of devices">{{i}}</option>
</select>
export class AppComponent {
  devices = 'one two three'.split(' ');
  selectedDevice = 'two';
  onChange(newValue) {
    console.log(newValue);
    this.selectedDevice = newValue;
    // ... do other stuff here ...
}

Se devicesfor uma matriz de objetos, vincule a em ngValuevez de value:

<select [ngModel]="selectedDeviceObj" (ngModelChange)="onChangeObj($event)" name="sel3">
  <option [ngValue]="i" *ngFor="let i of deviceObjects">{{i.name}}</option>
</select>
{{selectedDeviceObj | json}}
export class AppComponent {
  deviceObjects = [{name: 1}, {name: 2}, {name: 3}];
  selectedDeviceObj = this.deviceObjects[1];
  onChangeObj(newObj) {
    console.log(newObj);
    this.selectedDeviceObj = newObj;
    // ... do other stuff here ...
  }
}

Plunker- não usa <form>
Plunker- usa <form>e usa a nova API de formulários

Mark Rajcok
fonte
Anwere está certo, mas qual é o papel do ngModel aqui ainda estou confuso, você o explicará?
Pardeep Jain
11
O @PardeepJain, usando a ligação de dados bidirecional com o NgModel, faz com que o Angular 1) atualize automaticamente selectedDevicequando o usuário seleciona um item diferente e 2) se selectedDevicedefinirmos o valor de , o NgModel atualizará automaticamente a exibição. Como também queremos ser notificados de uma alteração, adicionei a (change)associação de eventos. Não devemos ter que fazer dessa maneira ... devemos poder dividir a ligação de dados bidirecional [ngModel]="selectedDevice" and (ngModelChange)="onChange($event)", mas, como descobri, onChange()é chamado duas vezes para cada lista de seleção alterada dessa maneira.
Mark Rajcok
ok thanx mais uma coisa, por favor. Eu quero obter o valor de: <option *ngFor="#course of course_array #i=index" #newone value={{course.id}} >{{course.course_name}}</option> course.course_namee course.idambos, como posso enviar esses dois via (alterar) função?
Pardeep Jain
11
@HongboMiao, a $eventvariável / símbolo especial faz parte do "contexto da instrução" que as instruções do modelo Angular possuem. Se em vez disso eu escrevi (ngModelChange)="onChange('abc')", newValueobteria a string abc. É apenas uma chamada de função JavaScript normal.
precisa saber é o seguinte
2
@ HongboMiao, use [ngValue] se você tiver uma matriz de objetos. Use [value] se você tiver uma matriz de tipos primitivos (string, booleano, inteiro).
21416 Mark-Rajcok
40

Você pode passar o valor de volta para o componente, criando uma variável de referência na tag select #devicee passando para o manipulador de alterações, que onChange($event, device.value)deve ter o novo valor

<select [(ng-model)]="selectedDevice" #device (change)="onChange($event, device.value)">
    <option *ng-for="#i of devices">{{i}}</option>
</select>

onChange($event, deviceValue) {
    console.log(deviceValue);
}
Brocco
fonte
11
Você não está vinculando ngModelaqui, está vinculando a uma nova variável chamada device.
lux
4
qual é o rolo [(ngModel)]daqui
Pardeep Jain
2
@Brocco Tanto o seu quanto o de Mark estão corretos. Espero que você possa entender. Só posso escolher uma resposta. :)
Hongbo Miao
22

Basta usar [ngValue] em vez de [value] !!

export class Organisation {
  description: string;
  id: string;
  name: string;
}
export class ScheduleComponent implements OnInit {
  selectedOrg: Organisation;
  orgs: Organisation[] = [];

  constructor(private organisationService: OrganisationService) {}

  get selectedOrgMod() {
    return this.selectedOrg;
  }

  set selectedOrgMod(value) {
    this.selectedOrg = value;
  }
}


<div class="form-group">
      <label for="organisation">Organisation
      <select id="organisation" class="form-control" [(ngModel)]="selectedOrgMod" required>
        <option *ngFor="let org of orgs" [ngValue]="org">{{org.name}}</option>
      </select>
      </label>
</div>
Robert King
fonte
11
Isso me ajudou. Não tenho certeza se meu caso é um pouco diferente, mas para mim (change)="selectOrg(selectedOrg)"chama a função selectOrg com a seleção atual / anterior, não a opção recém-selecionada. Eu descobri, eu nem preciso disso (change).
19416 Nick
Boa localização. sim, esse é um comportamento estranho ao passar (mudar) o modelo antigo. Eu pensei que seria como ng-change talvez seja um erro no angular2. Eu o atualizei para usar métodos get e set. Dessa forma, no método setOrgMod (valor) definido, posso saber que a organização mudou e atualizou minha lista de equipes organizacionais.
robert king
12

Corri para esse problema enquanto fazia o tutorial Angular 2 forms (versão TypeScript) em https://angular.io/docs/ts/latest/guide/forms.html

O bloco de seleção / opção não estava permitindo que o valor da seleção fosse alterado ao selecionar uma das opções.

Fazer o que Mark Rajcok sugeriu funcionou, embora eu esteja me perguntando se há algo que eu perdi no tutorial original ou se houve uma atualização. De qualquer forma, adicionar

onChange(newVal) {
    this.model.power = newVal;
}

para hero-form.component.ts na classe HeroFormComponent

e

(change)="onChange($event.target.value)"

para hero-form.component.html no <select>elemento fez com que funcionasse

jarisky
fonte
4

use selectionChange na angular 6 e acima. exemplo (selectionChange)= onChange($event.value)

namorados
fonte
Não usei a abordagem de formulário reativo. Só preciso do valor selecionado para acionar a chamada de serviço com base nesse valor único. O método acima me ajudou.
anavaras lamurep
3

Outra opção é armazenar o objeto em valor como uma string:

<select [ngModel]="selectedDevice | json" (ngModelChange)="onChange($event)">
    <option [value]="i | json" *ngFor="let i of devices">{{i}}</option>
</select>

componente:

onChange(val) {
    this.selectedDevice = JSON.parse(val);
}

Essa foi a única maneira de obter o trabalho de ligação bidirecional para definir o valor de seleção no carregamento da página. Isso ocorreu porque minha lista que preenche a caixa de seleção não era exatamente o mesmo objeto ao qual minha seleção estava vinculada e precisa ser o mesmo objeto, não apenas os mesmos valores de propriedade.

kravits88
fonte
3
<mat-form-field>
<mat-select placeholder="Vacancies" [(ngModel)]="vacanciesSpinnerSelectedItem.code" (ngModelChange)="spinnerClick1($event)"
    [ngModelOptions]="{standalone: true}" required>
    <mat-option *ngFor="let spinnerValue of vacanciesSpinnerValues" [value]="spinnerValue?.code">{{spinnerValue.description}}</mat-option>
</mat-select>

Eu usei isso para a lista suspensa de material angular. funciona bem

Apurv
fonte
1

A versão 3.2.0 iônica mais recente foi modificada (mudança) para (ionChange)

por exemplo: HTML

<ion-select (ionChange)="function($event)"> <ion-option>1<ion-option>
</ion-select>

TS

function($event){
// this gives the selected element
 console.log($event);

}
derrapagem
fonte
1

Angular 7/8

A partir do angular 6, o uso da propriedade de entrada ngModel com a diretiva de formulários reativos foi descontinuado e completamente removido no angular 7+. Leia o documento oficial aqui.

Usando a abordagem de formulário reativo, você pode obter / definir os dados selecionados como;

      //in your template
 <select formControlName="person" (change)="onChange($event)"class="form-control">
    <option [value]="null" disabled>Choose person</option>
      <option *ngFor="let person of persons" [value]="person"> 
        {{person.name}}
    </option>
 </select> 


 //in your ts
 onChange($event) {
    let person = this.peopleForm.get("person").value
    console.log("selected person--->", person);
    // this.peopleForm.get("person").setValue(person.id);
  }
7guyo
fonte
0

No Angular 5 eu fiz da seguinte maneira. obtenha o objeto $ event.value em vez de $ event.target.value

<mat-form-field color="warn">
   <mat-select (ngModelChange)="onChangeTown($event)" class="form-width" formControlName="branch" [(ngModel)]="branch" placeholder="Enter branch">
     <mat-option *ngFor="let branch of branchs" [value]="branch.value">
                  {{ branch.name }}
     </mat-option>
   </mat-select>
</mat-form-field>

onChangeTown(event): void {
  const selectedTown = event;
  console.log('selectedTown: ', selectedTown);
}
Kumaresan Perumal
fonte
0

No Angular 8 você pode simplesmente usar "selectionChange" assim:

 <mat-select  [(value)]="selectedData" (selectionChange)="onChange()" >
  <mat-option *ngFor="let i of data" [value]="i.ItemID">
  {{i.ItemName}}
  </mat-option>
 </mat-select>
B.Habibzadeh
fonte