¿Cómo puedo obtener una nueva selección en "select" en Angular 2?

372

Estoy usando Angular 2 (TypeScript).

Quiero hacer algo con la nueva selección, pero lo que obtengo onChange()es siempre la última selección. ¿Cómo puedo obtener la nueva selección?

<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
fuente

Respuestas:

751

Si no necesita enlace de datos bidireccional:

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

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

Para el enlace de datos bidireccional, separe los enlaces de eventos y propiedades:

<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 ...
}

Si deviceses una matriz de objetos, únete a en ngValuelugar 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- no usa <form>
Plunker- usa <form>y usa la nueva API de formularios

Mark Rajcok
fuente
Hay razón, pero ¿cuál es el papel de ngModelo aquí? Todavía estoy confundido. ¿Lo explicarán?
Pardeep Jain
1
@PardeepJain, el uso del enlace de datos bidireccional con NgModel hace que Angular 1) se actualice automáticamente selectedDevicecuando el usuario selecciona un elemento diferente, y 2) si establecemos el valor de selectedDevice, NgModel actualizará automáticamente la vista. Como también queremos recibir notificaciones de un cambio, agregué el (change)enlace del evento. No deberíamos tener que hacerlo de esta manera ... deberíamos poder dividir el enlace de datos bidireccional [ngModel]="selectedDevice" and (ngModelChange)="onChange($event)", pero como descubrí, onChange()se me llama dos veces por cada cambio de lista de selección de esa manera.
Mark Rajcok
Está bien, gracias una cosa más por favor. Quiero obtener el valor de: <option *ngFor="#course of course_array #i=index" #newone value={{course.id}} >{{course.course_name}}</option> course.course_namey course.idambos, ¿cómo puedo enviar estos dos a través de la función (cambio)?
Pardeep Jain
1
@HongboMiao, la $eventvariable / símbolo especial es parte del "contexto de declaración" que tienen las declaraciones de plantilla angular. Si en vez escribí (ngModelChange)="onChange('abc')"entonces newValuesería obtener la cadena abc. Es solo una función normal de JavaScript.
Mark Rajcok
2
@HongboMiao, use [ngValue] si tiene una matriz de objetos. Utilice [valor] si tiene una matriz de tipos primitivos (cadena, booleano, entero).
Mark Rajcok
40

Puede volver a pasar el valor al componente creando una variable de referencia en la etiqueta de selección #devicey pasándola al controlador de cambios onChange($event, device.value)debería tener el nuevo 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
fuente
1
No estás vinculando ngModelaquí, estás vinculando a una nueva variable llamada device.
lux
44
cuál es el rollo de [(ngModel)]aquí
Pardeep Jain
2
@Brocco Tanto el tuyo como el de Mark son correctos. Espero que puedas entender, solo puedo elegir una respuesta. :)
Hongbo Miao
22

¡Solo use [ngValue] en lugar 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
fuente
1
Esto me ayudo. No estoy seguro de si mi caso es ligeramente diferente, pero para mí (change)="selectOrg(selectedOrg)"llama a la función selectOrg con la selección actual / anterior, no la opción recién seleccionada. Me di cuenta, ni siquiera necesito el (change)bit.
Nick
Buen manchado. sí, ese es un comportamiento extraño con (cambio) pasando el modelo anterior. Pensé que sería como ng-change tal vez sea un error en angular2. Lo actualicé para usar métodos get y set. De esa forma, en el método setOrgMod (value) establecido, puedo saber que la organización ha cambiado y actualizar mi lista de equipos organizacionales.
Robert King
12

Me encontré con este problema mientras hacía el tutorial de formularios Angular 2 (versión TypeScript) en https://angular.io/docs/ts/latest/guide/forms.html

El bloque de selección / opción no permitía cambiar el valor de la selección seleccionando una de las opciones.

Hacer lo que sugirió Mark Rajcok funcionó, aunque me pregunto si hay algo que me perdí en el tutorial original o si hubo una actualización. En cualquier caso, agregando

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

a hero-form.component.ts en la clase HeroFormComponent

y

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

a hero-form.component.html en el <select>elemento lo hizo funcionar

jarisky
fuente
4

use selectionChange en angular 6 y superior. ejemplo (selectionChange)= onChange($event.value)

enamorado
fuente
No utilicé el enfoque de forma reactiva. Solo necesito el valor seleccionado para activar la llamada de servicio en función de ese valor único ... el método anterior me ayudó.
anavaras lamurep
3

Otra opción es almacenar el objeto en valor como una cadena:

<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);
}

Esta fue la única forma en que pude obtener un enlace bidireccional trabajando para establecer el valor de selección en la carga de la página. Esto se debió a que mi lista que llena el cuadro de selección no era exactamente el mismo objeto al que estaba vinculada mi selección y debe ser el mismo objeto, no solo los mismos valores de propiedad.

kravits88
fuente
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>

Utilicé esto para desplegar material angular. funciona bien

Apurv
fuente
1

El último iónico 3.2.0 ha modificado (cambio) a (ionChange)

por ejemplo: HTML

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

TS

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

}
patinar
fuente
1

Angular 7/8

A partir de angular 6, el uso de la propiedad de entrada ngModel con la directiva de formas reactivas se ha desaprobado y eliminado por completo en angular 7+. Lea el documento oficial aquí.

Usando el enfoque de forma reactiva puede obtener / establecer datos seleccionados 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
fuente
0

En Angular 5 lo hice de la siguiente manera. obtener el objeto $ event.value en lugar 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
fuente
0

En Angular 8 simplemente puede usar "selectionChange" de esta manera:

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