Bahan Sudut: mat-pilih tidak memilih default

109

Saya memiliki mat-pilih di mana opsi adalah semua objek yang ditentukan dalam array. Saya mencoba untuk mengatur nilai ke default ke salah satu opsi, namun itu dibiarkan dipilih saat halaman dirender.

File skrip ketikan saya berisi:

  public options2 = [
    {"id": 1, "name": "a"},
    {"id": 2, "name": "b"}
  ]
  public selected2 = this.options2[1].id;

File HTML saya berisi:

  <div>
    <mat-select
        [(value)]="selected2">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

Saya telah mencoba menyetel selected2dan valuemasuk mat-optionke objek dan id itu, dan telah mencoba menggunakan keduanya[(value)] dan [(ngModel)]di mat-select, tetapi tidak ada yang berfungsi.

Saya menggunakan materi versi 2.0.0-beta.10

William Moore
sumber
2
Gunakan compareWith. Lebih elegan.
Badis Merabet
HARUS compareWithDIMILIKI, lihat jawaban badis di sini stackoverflow.com/questions/47333171/…
bresleveloper

Jawaban:

144

Gunakan pengikatan untuk nilai di template Anda.

value="{{ option.id }}"

seharusnya

[value]="option.id"

Dan dalam penggunaan nilai yang Anda pilih, ngModelbukan value.

<mat-select [(value)]="selected2">

seharusnya

<mat-select [(ngModel)]="selected2">

Kode lengkap:

<div>
  <mat-select [(ngModel)]="selected2">
    <mat-option *ngFor="let option of options2" [value]="option.id">{{ option.name }}</mat-option>
  </mat-select>
</div>

Di samping catatan pada versi 2.0.0-beta.12 pemilihan material sekarang menerima mat-form-fieldelemen sebagai elemen induk sehingga konsisten dengan kontrol masukan material lainnya. Ganti divelemen dengan mat-form-fieldelemen setelah Anda meningkatkan.

<mat-form-field>
  <mat-select [(ngModel)]="selected2">
    <mat-option *ngFor="let option of options2" [value]="option.id">{{ option.name }}</mat-option>
  </mat-select>
</mat-form-field>
Igor
sumber
10
"Sepertinya Anda menggunakan ngModel pada kolom formulir yang sama dengan formControlName. Dukungan untuk menggunakan properti input ngModel dan acara ngModelChange dengan arahan formulir reaktif tidak digunakan lagi di Angular v6 dan akan dihapus di Angular v7. Untuk informasi selengkapnya tentang ini , lihat dokumen API kami di sini: angular.io/api/forms/FormControlName#use-with-ngmodel "
ldgorman
1
@ldgorman - Saya tidak mengerti bagaimana Anda menarik kesimpulan itu. Jika Anda mengacu pada mat-form-field, ini ..."used to wrap several Angular Material components and apply common Text field styles", jadi bukan hal yang sama. Selain itu OP dan juga jawaban saya tidak menyebutkan FormControl, FormGroup, atau FormControlName.
Igor
1
Saya mengalami masalah yang sama bahkan setelah menerapkan kode yang sama seperti di atas @Igor
Chuck
@Chuck - Jika Anda masih mengalami masalah, harap ajukan pertanyaan baru dan sertakan contoh minimal yang dapat direproduksi . Jika Anda ingin saya melihatnya, Anda dapat membalas komentar ini dengan tautan ke pertanyaan itu.
Igor
2
@ Igor- Kami menemukan jawabannya, nilai dikembalikan sebagai angka dan Mat-pilih itu mencari string. [compareWith]direktif adalah apa yang kami gunakan
Chuck
94

Gunakan compareWith, fungsi untuk membandingkan nilai opsi dengan nilai yang dipilih. lihat di sini: https://material.angular.io/components/select/api#MatSelect

Untuk objek dengan struktur berikut:

listOfObjs = [{ name: 'john', id: '1'}, { name: 'jimmy', id: '2'},...]

Tentukan markup seperti ini:

<mat-form-field>
  <mat-select
    [compareWith]="compareObjects"
    [(ngModel)]="obj">
       <mat-option  *ngFor="let obj of listOfObjs" [value]="obj">
          {{ obj.name }}
       </mat-option>
    </mat-select>
</mat-form-field>

Dan tentukan fungsi perbandingan seperti ini:

compareObjects(o1: any, o2: any): boolean {
  return o1.name === o2.name && o1.id === o2.id;
}
Badis Merabet
sumber
8
Sempurna saat menangani objek dan bukan array sederhana. Terima kasih.
Riaan van Zyl
25

Saya menggunakan Angular 5 dan bentuk reaktif dengan mat-pilih dan tidak bisa mendapatkan salah satu solusi di atas untuk menampilkan nilai awal.

Saya harus menambahkan [bandingkanWith] untuk menangani berbagai jenis yang digunakan dalam komponen mat-pilih. Secara internal, mat-pilih menggunakan array untuk menampung nilai yang dipilih. Ini memungkinkan kode yang sama untuk bekerja dengan beberapa pilihan jika mode itu diaktifkan.

Angular Select Control Doc

Inilah solusi saya:

Form Builder untuk menginisialisasi kontrol formulir:

this.formGroup = this.fb.group({
    country: new FormControl([ this.myRecord.country.id ] ),
    ...
});

Kemudian implementasikan fungsi bandingkanWith pada komponen Anda:

compareIds(id1: any, id2: any): boolean {
    const a1 = determineId(id1);
    const a2 = determineId(id2);
    return a1 === a2;
}

Selanjutnya buat dan ekspor fungsi determId (saya harus membuat fungsi mandiri sehingga mat-pilih dapat menggunakannya):

export function determineId(id: any): string {
    if (id.constructor.name === 'array' && id.length > 0) {
       return '' + id[0];
    }
    return '' + id;
}

Terakhir tambahkan atribut bandingkanWith ke mat-pilih Anda:

<mat-form-field hintLabel="select one">
<mat-select placeholder="Country" formControlName="country" 
    [compareWith]="compareIds">

    <mat-option>None</mat-option>
    <mat-option *ngFor="let country of countries" [value]="country.id">
                        {{ country.name }}
    </mat-option>
</mat-select>
</mat-form-field>
Heather92065
sumber
Terima kasih banyak! Sangat sulit untuk menemukan penyebabnya.
Pax Beach
@ Heather92065 Ini adalah satu-satunya solusi yang berhasil untuk saya. Saya sangat berterima kasih kepada Anda!
Latin Warrior
16

Anda harus mengikatnya seperti [value]di mat-optionbawah ini,

<mat-select placeholder="Panel color" [(value)]="selected2">
  <mat-option *ngFor="let option of options2" [value]="option.id">
    {{ option.name }}
  </mat-option>
</mat-select>

DEMO LANGSUNG

Aravind
sumber
Ini bekerja dengan sempurna. Insted menggunakan ngModel atau setValue () ini adalah metode termudah dan sempurna
Rohit Parte
10

Anda cukup menerapkan fungsi perbandingan Anda sendiri

[compareWith]="compareItems"

Lihat juga dokumennya . Jadi kode lengkapnya akan terlihat seperti ini:

  <div>
    <mat-select
        [(value)]="selected2" [compareWith]="compareItems">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

dan di file Ketikan:

  compareItems(i1, i2) {
    return i1 && i2 && i1.id===i2.id;
  }
Leo
sumber
Ini berhasil untuk saya dan saya pikir ini sebagian besar cara yang benar tetapi jika daftar hanya berisi satu elemen itu tidak berfungsi. Terima kasih
Kode Kadiya
Jenis pengecualian apa yang Anda dapatkan hanya dengan satu elemen? Karena perbandingan harus bertanggung jawab jika i1atau i2tidak akan ada.
LeO
6

Seperti yang telah disebutkan di Angular 6 menggunakan ngModel dalam bentuk reaktif tidak digunakan lagi (dan dihapus di Angular 7), jadi saya memodifikasi template dan komponennya sebagai berikut.

Templatenya:

<mat-form-field>
    <mat-select [formControl]="filter" multiple 
                [compareWith]="compareFn">
        <mat-option *ngFor="let v of values" [value]="v">{{v.label}}</mat-option>
    </mat-select>
</mat-form-field>

Bagian utama komponen ( onChangesdan detail lainnya dihilangkan):

interface SelectItem {
    label: string;
    value: any;
}

export class FilterComponent implements OnInit {
    filter = new FormControl();

    @Input
    selected: SelectItem[] = [];

    @Input()
    values: SelectItem[] = [];

    constructor() { }

    ngOnInit() {
        this.filter.setValue(this.selected);
    }

    compareFn(v1: SelectItem, v2: SelectItem): boolean {
        return compareFn(v1, v2);
    }
}

function compareFn(v1: SelectItem, v2: SelectItem): boolean {
    return v1 && v2 ? v1.value === v2.value : v1 === v2;
}

Catat this.filter.setValue (this.selected) di ngOnInitatas.

Tampaknya berfungsi di Angular 6.

mp31415
sumber
Ini seharusnya menjadi jawaban terbaik, karena ini juga mencakup pilihan objek saat berhadapan dengan dua hasil API yang berbeda untuk dibandingkan.
Marco Klein
(mis. Daftar total item untuk dipilih dan item yang dipilih dalam panggilan api lain).
Marco Klein
Angular 7 masih berfungsi dengan model penggerak template! Tetapi Anda tidak dapat mencampurnya dengan bentuk reaktif pada template yang sama. Petunjuk Anda dengan [compareWith]hebat
LeO
3

Saya melakukannya seperti dalam contoh ini. Mencoba untuk mengatur nilai mat-pilih ke nilai dari salah satu mat-pilihan. Tapi gagal.

Kesalahan saya adalah melakukan [(value)] = "someNumberVariable" ke variabel tipe numerik sedangkan yang ada di opsi-mat adalah string. Bahkan jika mereka tampak sama di template itu tidak akan memilih opsi itu.

Setelah saya mengurai someNumberVariable menjadi string semuanya baik-baik saja.

Jadi sepertinya Anda perlu memiliki mat-pilih dan nilai mat-option tidak hanya angka yang sama (jika Anda menyajikan angka) tetapi juga membiarkannya menjadi tipe string.

jg80.dll
sumber
Itu juga masalah saya. Yang satu numerik, yang lainnya string.
Vadim Berman
2

Solusi bagi saya adalah:

<mat-form-field>
  <mat-select #monedaSelect  formControlName="monedaDebito" [attr.disabled]="isLoading" [placeholder]="monedaLabel | async ">
  <mat-option *ngFor="let moneda of monedasList" [value]="moneda.id">{{moneda.detalle}}</mat-option>
</mat-select>

TS:

@ViewChild('monedaSelect') public monedaSelect: MatSelect;
this.genericService.getOpciones().subscribe(res => {

  this.monedasList = res;
  this.monedaSelect._onChange(res[0].id);


});

Menggunakan objek: {id: number, detalle: string}

Seba Arce
sumber
1

Coba ini!

this.selectedObjectList = [{id:1}, {id:2}, {id:3}]
this.allObjectList = [{id:1}, {id:2}, {id:3}, {id:4}, {id:5}]
let newList = this.allObjectList.filter(e => this.selectedObjectList.find(a => e.id == a.id))
this.selectedObjectList = newList
Facu Quintana
sumber
1

Solusi saya sedikit rumit dan sederhana.

<div>
    <mat-select
        [placeholder]="selected2">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

Saya baru saja menggunakan placeholder . Warna default placeholder material adalah light gray. Agar terlihat seperti opsi yang dipilih, saya hanya memanipulasi CSS sebagai berikut:

::ng-deep .mat-select-placeholder {
    color: black;
}
Steffi Keran Rani J
sumber
1

Pengikatan atau pengaturan nilai default hanya berfungsi jika atribut nilai pada MatSelect sebanding dengan atribut nilai yang diikat ke MatOption . Jika Anda mengikat captionitem ke atribut value dari elemen mat-option, Anda juga harus menyetel elemen default pada mat-select ke captionitem Anda. Jika Anda mengikatId item Anda ke mat-option , Anda harus mengikat idke mat-select juga, bukan keseluruhan item, caption atau lainnya, hanya bidang yang sama.

Tetapi Anda perlu melakukannya dengan mengikat []

Dominik Miedziński
sumber
1

Saya mengikuti langkah-langkah di atas dengan sangat hati-hati dan masih belum bisa memilih nilai awal.

Alasannya adalah meskipun nilai terikat saya didefinisikan sebagai string dalam skrip tipe, API backend saya mengembalikan angka.

Pengetikan longgar Javascript hanya mengubah jenis saat runtime (tanpa kesalahan), yang mencegah pemilihan nilai awal.

Komponen

myBoundValue: string;

Template

<mat-select [(ngModel)]="myBoundValue">

Solusinya adalah memperbarui API untuk mengembalikan nilai string.

Alex Cooper
sumber
1

Cara yang sangat sederhana untuk mencapai ini adalah menggunakan formControldengan nilai default, di dalam a FormGroup(opsional) misalnya. Ini adalah contoh menggunakan selektor unit ke input area:

ts

H_AREA_UNIT = 1;
M_AREA_UNIT = 2;

exampleForm: FormGroup;

this.exampleForm = this.formBuilder.group({
  areaUnit: [this.H_AREA_UNIT],
});

html

<form [formGroup]="exampleForm">
 <mat-form-field>
   <mat-label>Unit</mat-label>
   <mat-select formControlName="areaUnit">
     <mat-option [value]="H_AREA_UNIT">h</mat-option>
     <mat-option [value]="M_AREA_UNIT">m</mat-option>
   </mat-select>
 </mat-form-field>
</form>
Juan Antonio
sumber
0

Perbandingan antara angka dan string digunakan untuk menjadi salah , jadi, berikan nilai yang Anda pilih ke string dalam ngOnInit dan itu akan berhasil.

Saya memiliki masalah yang sama, saya mengisi mat-pilih dengan enum, menggunakan

Object.keys(MyAwesomeEnum).filter(k => !isNaN(Number(k)));

dan saya memiliki nilai enum yang ingin saya pilih ...

Saya menghabiskan beberapa jam berjuang dengan pikiran saya mencoba untuk mengidentifikasi mengapa itu tidak berhasil. Dan saya melakukannya setelah merender semua variabel yang digunakan di mat-pilih, koleksi kunci dan yang dipilih ... jika Anda memiliki ["0", "1", "2"] dan ingin memilih 1 ( yang merupakan angka) 1 == "1" salah dan karena itu tidak ada yang dipilih.

jadi, solusinya adalah memberikan Anda nilai yang dipilih ke string dalam ngOnInit dan itu akan berhasil.

Juan
sumber
1
Halo Juan, Anda mungkin ingin melihat posting ini yang membahas detail tentang operator kesetaraan yang berbeda di JS: stackoverflow.com/questions/359494/…
William Moore
Hai William, itu pos yang bagus, saya pernah ke sana beberapa kali ... Dan saya belajar cara membandingkan dengan benar (saya harap, dan saya selalu dapat meninjau dokumen) ... Masalahnya di sini adalah bahwa binding, dipaksa oleh Pengontrol material, di mana menggunakan jenis, nomor dan string yang berbeda ... Pengontrol itu mengharapkan memiliki jenis yang sama, jadi, jika yang dipilih adalah nomor, koleksi harus berupa kumpulan nomor ... Itu masalahnya.
Juan
0

Saya melakukan ini.

<div>
    <mat-select [(ngModel)]="selected">
        <mat-option *ngFor="let option of options" 
            [value]="option.id === selected.id ? selected : option">
            {{ option.name }}
        </mat-option>
    </mat-select>
</div>

Biasanya Anda bisa melakukannya [value]="option", kecuali Anda mendapatkan opsi dari beberapa database ?? Saya pikir baik penundaan mendapatkan data menyebabkannya tidak berfungsi, atau objek yang didapat berbeda dalam beberapa hal meskipun mereka sama ?? Cukup aneh kemungkinan besar yang kemudian, karena saya juga mencoba [value]="option === selected ? selected : option"dan tidak berhasil.

Cupu
sumber
0

TS

   optionsFG: FormGroup;
   this.optionsFG = this.fb.group({
       optionValue: [null, Validators.required]
   });

   this.optionsFG.get('optionValue').setValue(option[0]); //option is the arrayName

HTML

   <div class="text-right" [formGroup]="optionsFG">
     <mat-form-field>
         <mat-select placeholder="Category" formControlName="optionValue">
           <mat-option *ngFor="let option of options;let i =index" [value]="option">
            {{option.Value}}
          </mat-option>
        </mat-select>
      </mat-form-field>
  </div>
Arokia Lijas
sumber
0

public options2 = [
  {"id": 1, "name": "a"},
  {"id": 2, "name": "b"}
]
 
YourFormGroup = FormGroup; 
mode: 'create' | 'update' = 'create';

constructor(@Inject(MAT_DIALOG_DATA) private defaults: defautValuesCpnt,
      private fb: FormBuilder,
      private cd: ChangeDetectorRef) {
}
  
ngOnInit() {

  if (this.defaults) {
    this.mode = 'update';
  } else {
    this.defaults = {} as Cpnt;
  }

  this.YourFormGroup.patchValue({
    ...
    fCtrlName: this.options2.find(x => x.name === this.defaults.name).id,
    ... 
  });

  this.YourFormGroup = this.fb.group({
    fCtrlName: [ , Validators.required]
  });

}
  <div>
    <mat-select formControlName="fCtrlName"> <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

lilandos didas
sumber
Ini akan membantu saat Anda menggunakan Edit & Update di komponen aman,
lilandos didas