Associare l'elemento selezionato all'oggetto in Angolare


409

Vorrei associare un elemento selezionato a un elenco di oggetti, il che è abbastanza semplice:

@Component({
   selector: 'myApp',
   template: `<h1>My Application</h1>
              <select [(ngModel)]="selectedValue">
                 <option *ngFor="#c of countries" value="c.id">{{c.name}}</option>
              </select>`
})
export class AppComponent{
    countries = [
       {id: 1, name: "United States"},
       {id: 2, name: "Australia"}
       {id: 3, name: "Canada"},
       {id: 4, name: "Brazil"},
       {id: 5, name: "England"}
     ];
    selectedValue = null;
}

In questo caso, sembra che selectedValuesarebbe un numero - l'id dell'elemento selezionato.

Tuttavia, in realtà mi piacerebbe legare l'oggetto paese stesso in modo che selectedValuesia l'oggetto piuttosto che solo l'id. Ho provato a modificare il valore dell'opzione in questo modo:

<option *ngFor="#c of countries" value="c">{{c.name}}</option>

ma questo non sembra funzionare. Sembra posizionare un oggetto nel mio selectedValue- ma non l'oggetto che mi aspetto. Puoi vederlo nel mio esempio di Plunker .

Ho anche provato ad associare l'evento change in modo da poter impostare l'oggetto da solo in base all'ID selezionato; tuttavia, sembra che l'evento change si attivi prima che venga aggiornato ngModel, il che significa che non ho accesso al nuovo valore selezionato in quel punto.

Esiste un modo semplice per associare un elemento select a un oggetto con Angular 2?


Ho appena realizzato che il mio Plunk funziona in modo leggermente diverso in IE rispetto a Chrome. Nessuno dei due funziona nel modo che desidero, ma FYI.
RHarris,

Risposte:


735
<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
  <option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>

Esempio StackBlitz

NOTA: è possibile utilizzare al [ngValue]="c"posto di [ngValue]="c.id"dove c è l'oggetto Paese completo.

[value]="..."supporta solo i valori di stringa
[ngValue]="..."supporta qualsiasi tipo

aggiornare

Se valueè un oggetto, l'istanza preselezionata deve essere identica a uno dei valori.

Vedi anche il confronto personalizzato aggiunto di recente https://github.com/angular/angular/issues/13268 disponibile da 4.0.0-beta.7

<select [compareWith]="compareFn" ...

Abbi cura di te se vuoi accedere thisall'interno compareFn.

compareFn = this._compareFn.bind(this);

// or 
// compareFn = (a, b) => this._compareFn(a, b);

_compareFn(a, b) {
   // Handle compare logic (eg check if unique ids are the same)
   return a.id === b.id;
}

21
Ho provato ma questo sembra legare i dati solo dal menu a discesa al modello. Se si accede alla pagina con il modello già impostato, il menu a discesa non viene impostato di conseguenza ...
Strinder,

13
@Strinder un errore frequente è utilizzare un'altra istanza di oggetto per selectedValuerispetto a per cdi (l'elemento predefinito). Un oggetto diverso anche con le stesse proprietà e valori non funziona, deve essere la stessa istanza di oggetto.
Günter Zöchbauer,

1
@ GünterZöchbauer Sì. Già pensato al pensiero. Quindi non esiste un modo semplice per sincronizzare direttamente con il modello e un elenco di valori? = sempre tramite onChange?
Strinder,

1
Presto potremmo essere in grado di confrontare gli oggetti ngModel in base alle loro proprietà utilizzando la funzione di confronto personalizzata. Basta guardare questo problema: github.com/angular/angular/issues/13268
kub1x

1
È sempre facile quando lo conosci ;-) ma angular.io/api/forms/NgSelectOption#description contiene un link angular.io/api/forms/SelectControlValueAccessor con buoni documenti.
Günter Zöchbauer,

41

Questo potrebbe aiutare:

    <select [(ngModel)]="selectedValue">
          <option *ngFor="#c of countries" [value]="c.id">{{c.name}}</option>
    </select>

5
Ho usato [valore] invece di [ngValue]. Non è lo stesso. Questo ha funzionato per me
Carolina Faedo,

2
Errore su "#" nell'angolo 4
mare-kg

2
Usa al letposto di #@ sea-kg
Ashraful Islam il

1
Questa risposta non ottiene il valore selezionato
San Jaisy,

20

Puoi farlo anche senza la necessità di utilizzarlo [(ngModel)]nel tuo <select>tag

Dichiarare una variabile nel file ts

toStr = JSON.stringify;

e nel tuo modello fai questo

 <option *ngFor="let v of values;" [value]="toStr(v)">
      {{v}}
 </option>

e quindi usare

let value=JSON.parse(event.target.value)

per analizzare nuovamente la stringa in un oggetto JavaScript valido


1
Questo è davvero fattibile, ma su oggetti di grandi dimensioni diventerà un dolore. Inoltre, la capacità sottolineata di Angular di rilevare i cambiamenti è qualcosa a cui pensare. Trasmettere informazioni come json, facilmente analizzabili dai robot, aumenta le prestazioni. L'uso del rilevamento delle modifiche di Angular nasconde (incapsula) la logica dei dati e ti assicura le informazioni necessarie. @ Günter Zöchbauer la risposta è il modo di farlo in angolare. :)
Lucaci Andrei il

Mi ha aiutato dove avevo un unico elenco e la modifica di un valore non dovrebbe aggiornare il successivo, quindi mi ha aiutato a usarlo come un hack senza l'uso di ngmodel, grazie :)
Melvin,

Funziona con semplici oggetti JavaScript ma nota per le istanze di una classe che perderebbero tutti i metodi.
KhalilRavanna,

13

Ha funzionato per me:

HTML modello:

Ho aggiunto (ngModelChange)="selectChange($event)"al mio select.

<div>
  <label for="myListOptions">My List Options</label>
  <select (ngModelChange)="selectChange($event)" [(ngModel)]=model.myListOptions.id >
    <option *ngFor="let oneOption of listOptions" [ngValue]="oneOption.id">{{oneOption.name}}</option>
  </select>
</div>

Su component.ts:

  listOptions = [
    { id: 0, name: "Perfect" },
    { id: 1, name: "Low" },
    { id: 2, name: "Minor" },
    { id: 3, name: "High" },
  ];

È necessario aggiungere a component.tsquesta funzione:

  selectChange( $event) {
    //In my case $event come with a id value
    this.model.myListOptions = this.listOptions[$event];
  }

Nota: provo con [select]="oneOption.id==model.myListOptions.id"e non lavoro.

============= Un altro modo può essere: =========

HTML modello:

Ho aggiunto [compareWith]="compareByOptionIdal mio select.

<div>
  <label for="myListOptions">My List Options</label>
  <select [(ngModel)]=model.myListOptions [compareWith]="compareByOptionId">
    <option *ngFor="let oneOption of listOptions" [ngValue]="oneOption">{{oneOption.name}}</option>
  </select>
</div>

Su component.ts:

  listOptions = [
    { id: 0, name: "Perfect" },
    { id: 1, name: "Low" },
    { id: 2, name: "Minor" },
    { id: 3, name: "High" },
  ];

È necessario aggiungere a component.tsquesta funzione:

 /* Return true or false if it is the selected */
 compareByOptionId(idFist, idSecond) {
    return idFist && idSecond && idFist.id == idSecond.id;
 }

Questo è utile se vuoi anche gestire l'evento change per fare qualcosa in più (come informare un callback di change). Tuttavia, in tal caso, è sufficiente inserire [ngModel]e quindi impostare manualmente il modello nel callback della modifica personalizzata definito in (ngModelChange).
schiaccia

9

Nel caso in cui qualcuno stia cercando di fare lo stesso usando i moduli reattivi:

<form [formGroup]="form">
  <select formControlName="country">
    <option *ngFor="let country of countries" [ngValue]="country">{{country.name}}</option>
  </select>
  <p>Selected Country: {{country?.name}}</p>
</form>

Controlla qui l' esempio funzionante


5

È possibile selezionare l'id utilizzando una funzione

<option *ngFor="#c of countries" (change)="onchange(c.id)">{{c.name}}</option>

4

Per me funziona così, puoi consolarlo event.target.value.

<select (change) = "ChangeValue($event)" (ngModel)="opt">   
    <option *ngFor=" let opt of titleArr" [value]="opt"></option>
</select>

2

Inoltre, se nient'altro da determinate soluzioni non funziona, controlla se hai importato "FormsModule" all'interno di "AppModule", questa è stata la chiave per me.


2

Crea un altro getter per l'elemento selezionato

<form [formGroup]="countryForm">
  <select formControlName="country">
    <option *ngFor="let c of countries" [value]="c.id">{{c.name}}</option>
  </select>

  <p>Selected Country: {{selectedCountry?.name}}</p>
</form>

In ts:

get selectedCountry(){
  let countryId = this.countryForm.controls.country.value;
  let selected = this.countries.find(c=> c.id == countryId);
  return selected;
}

1

È possibile ottenere il valore selezionato anche con l'aiuto di click () passando il valore selezionato attraverso la funzione

<md-select placeholder="Select Categorie"  
    name="Select Categorie" >
  <md-option *ngFor="let list of categ" [value]="list.value" (click)="sub_cat(list.category_id)" >
    {{ list.category }}
  </md-option>
</md-select>

0

usa così anche ..

<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
     <option *ngFor="let c of countries" value="{{c.id}}">{{c.name}}</option>
 </select>

0

In app.component.html:

 <select type="number" [(ngModel)]="selectedLevel">
          <option *ngFor="let level of levels" [ngValue]="level">{{level.name}}</option>
        </select>

E app.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  levelNum:number;
  levels:Array<Object> = [
      {num: 0, name: "AA"},
      {num: 1, name: "BB"}
  ];

  toNumber(){
    this.levelNum = +this.levelNum;
    console.log(this.levelNum);
  }

  selectedLevel = this.levels[0];

  selectedLevelCustomCompare = {num: 1, name: "BB"}

  compareFn(a, b) {
    console.log(a, b, a && b && a.num == b.num);
    return a && b && a.num == b.num;
  }
}

0

<select name="typeFather"
    [(ngModel)]="type.typeFather">
        <option *ngFor="let type of types" [ngValue]="type">{{type.title}}</option>
</select>

quell'approccio funzionerà sempre, tuttavia Se hai un elenco dinamico, assicurati di caricarlo prima del modello

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.