Mengikat elemen pilih ke objek di Angular

409

Saya ingin mengikat elemen pilih ke daftar objek - yang cukup mudah:

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

Dalam hal ini, tampaknya itu selectedValueakan menjadi nomor - id dari item yang dipilih.

Namun, saya sebenarnya ingin mengikat objek negara itu sendiri sehingga selectedValueobjeknya bukan hanya id. Saya mencoba mengubah nilai opsi seperti:

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

tapi ini sepertinya tidak berhasil. Tampaknya menempatkan objek di saya selectedValue- tetapi bukan objek yang saya harapkan. Anda dapat melihat ini dalam contoh Plunker saya .

Saya juga mencoba mengikat ke acara perubahan sehingga saya bisa mengatur sendiri objek berdasarkan id yang dipilih; Namun, tampaknya acara perubahan diaktifkan sebelum ngModel terikat diperbarui - artinya saya tidak memiliki akses ke nilai yang baru dipilih pada saat itu.

Apakah ada cara bersih untuk mengikat elemen pilih ke objek dengan Angular 2?

RHarris
sumber
Baru sadar Plunk saya bekerja sedikit berbeda di IE vs Chrome. Tidak ada yang benar-benar bekerja seperti yang saya inginkan, tetapi FYI.
RHarris

Jawaban:

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

Contoh StackBlitz

CATATAN: Anda dapat menggunakan [ngValue]="c"alih-alih di [ngValue]="c.id"mana c adalah objek negara yang lengkap.

[value]="..."hanya mendukung nilai string yang
[ngValue]="..."mendukung tipe apa pun

memperbarui

Jika valueobjek, instance yang dipilih harus identik dengan salah satu nilai.

Lihat juga perbandingan ubahsuaian yang baru ditambahkan https://github.com/angular/angular/issues/13268 tersedia sejak 4.0.0-beta.7

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

Berhati-hatilah jika Anda ingin mengakses di thisdalam 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;
}
Günter Zöchbauer
sumber
21
Sudah mencobanya tetapi ini sepertinya hanya mengikat data dari Dropdown ke model. Jika memasuki halaman dengan model yang sudah diatur dropdown tidak diatur sesuai ...
Strinder
13
@ Strinder kesalahan yang sering terjadi adalah menggunakan instance objek lain untuk selectedValuedaripada untuk c(item default). Objek yang berbeda bahkan dengan properti dan nilai yang sama tidak berfungsi, itu harus berupa instance objek yang sama.
Günter Zöchbauer
1
@ GünterZöchbauer Ya. Sudah memikirkan pikiran. Jadi tidak ada cara mudah untuk menyinkronkan langsung dengan model dan daftar nilai? = selalu via onChange?
Strinder
1
Segera kami mungkin dapat membandingkan objek ngModel dengan propertinya menggunakan fungsi komparator kustom. Lihat saja masalah ini: github.com/angular/angular/issues/13268
kub1x
1
Selalu mudah setelah Anda mengetahuinya ;-) tetapi angular.io/api/forms/NgSelectOption#description berisi tautan angular.io/api/forms/SelectControlValueAccessor dengan dokumen yang baik.
Günter Zöchbauer
41

Ini bisa membantu:

    <select [(ngModel)]="selectedValue">
          <option *ngFor="#c of countries" [value]="c.id">{{c.name}}</option>
    </select>
Carolina Faedo
sumber
5
Saya telah menggunakan [nilai] bukan [ngValue]. Ini tidak sama. Ini berhasil untuk saya
Carolina Faedo
2
Kesalahan pada '#' di sudut 4
laut-kg
2
Gunakan letsebagai ganti #@ sea-kg
Ashraful Islam
1
Jawaban ini tidak mendapatkan nilai yang dipilih
San Jaisy
20

Anda dapat melakukan ini juga tanpa perlu menggunakan tag [(ngModel)]Anda<select>

Deklarasikan variabel dalam file ts Anda

toStr = JSON.stringify;

dan dalam template Anda lakukan ini

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

dan kemudian gunakan

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

untuk mengurai string kembali ke objek JavaScript yang valid

Rahul Kumar
sumber
1
Ini memang bisa dilakukan, tetapi pada benda besar akan terasa menyebalkan. Juga, kemampuan garis bawah Angular tentang deteksi perubahan adalah sesuatu yang harus dipikirkan. Mengeluarkan informasi sebagai json, mudah diurai oleh bot, menambah kinerja pengangkutan. Menggunakan deteksi perubahan Angular menyembunyikan (merangkum) logika data, dan meyakinkan Anda tentang informasi yang Anda butuhkan. @ Günter Zöchbauer jawabannya adalah cara untuk melakukannya di Angular. :)
Lucaci Andrei
Membantu saya di mana saya memiliki satu daftar dan mengubah satu nilai tidak harus memperbarui berikutnya sehingga membantu menggunakan ini sebagai peretasan tanpa menggunakan ngmodel, Terima kasih :)
Melvin
Ini berfungsi untuk objek JavaScript biasa tetapi perhatikan untuk instance kelas Anda akan kehilangan semua metode di atasnya.
KhalilRavanna
13

Ini bekerja untuk saya:

HTML templat:

Saya menambahkan (ngModelChange)="selectChange($event)"ke 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>

Pada component.ts:

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

Anda perlu menambahkan ke component.tsfungsi ini:

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

Catatan: Saya mencoba [select]="oneOption.id==model.myListOptions.id"dan tidak bekerja.

============= Cara lain dapat: =========

HTML templat:

Saya menambahkan [compareWith]="compareByOptionIdke 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>

Pada component.ts:

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

Anda perlu menambahkan ke component.tsfungsi ini:

 /* Return true or false if it is the selected */
 compareByOptionId(idFist, idSecond) {
    return idFist && idSecond && idFist.id == idSecond.id;
 }
Jose Carlos Ramos Carmenates
sumber
Ini bagus jika Anda juga ingin menangani acara perubahan untuk melakukan sesuatu yang ekstra (seperti informasikan perubahan panggilan balik). Meskipun dalam kasus itu, Anda hanya perlu meletakkan [ngModel]dan kemudian mengatur model Anda secara manual di custom callback perubahan yang ditentukan dalam (ngModelChange).
naksir
9

Untuk berjaga-jaga jika seseorang ingin melakukan hal yang sama menggunakan Formulir Reaktif:

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

Lihat contoh kerja di sini

Elvin
sumber
5

Anda Dapat Memilih Id menggunakan Fungsi

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

Bagi saya ini berfungsi seperti ini, Anda dapat menghibur event.target.value.

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

Juga, jika tidak ada hal lain dari solusi yang diberikan tidak berfungsi, periksa apakah Anda mengimpor "FormsModule" di dalam "AppModule", itu adalah kunci bagi saya.

nikola.maksimovic
sumber
2

Buat pengambil lain untuk item yang dipilih

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

Dalam ts:

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

Anda bisa mendapatkan nilai yang dipilih juga dengan bantuan klik () dengan melewatkan nilai yang dipilih melalui fungsi

<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>
Jose Kj
sumber
0

gunakan cara ini juga ..

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

Dalam app.component.html:

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

Dan 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;
  }
}
Mojtaba Nava
sumber
0

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

pendekatan itu akan selalu berhasil, namun Jika Anda memiliki daftar dinamis, pastikan Anda memuatnya sebelum model

Jack Sowell
sumber