Angular Material: mat-select ไม่ได้เลือกค่าเริ่มต้น


109

ฉันมี mat-select โดยที่อ็อพชันคืออ็อบเจ็กต์ทั้งหมดที่กำหนดไว้ในอาร์เรย์ ฉันพยายามตั้งค่าเป็นค่าเริ่มต้นเป็นหนึ่งในตัวเลือก แต่จะถูกเลือกทิ้งไว้เมื่อหน้าแสดงผล

ไฟล์ typescript ของฉันประกอบด้วย:

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

ไฟล์ HTML ของฉันประกอบด้วย:

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

ฉันได้ลองการตั้งค่าselected2และvalueในmat-optionทั้งอ็อบเจ็กต์และ id แล้วและได้ลองใช้ทั้งสองอย่าง[(value)]และ[(ngModel)]ในmat-selectแต่ไม่มีการทำงาน

ฉันใช้วัสดุเวอร์ชัน 2.0.0-beta.10


2
ใช้compareWith. มันสง่างามมากขึ้น
Badis Merabet

ต้องมีcompareWithดูคำตอบของ badis ที่นี่stackoverflow.com/questions/47333171/…
bresleveloper

คำตอบ:


144

ใช้การผูกสำหรับค่าในเทมเพลตของคุณ

value="{{ option.id }}"

ควรจะเป็น

[value]="option.id"

และในการใช้งานคุ้มค่าที่คุณเลือกแทนngModelvalue

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

ควรจะเป็น

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

รหัสที่สมบูรณ์:

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

สังเกตด้านบนเป็นของรุ่น 2.0.0-beta.12 วัสดุที่เลือกในขณะนี้ยอมรับmat-form-fieldองค์ประกอบเป็นองค์ประกอบหลักดังนั้นจึงมีความสอดคล้องกับคนอื่น ๆ ควบคุมการนำเข้าวัสดุ แทนที่divองค์ประกอบด้วยmat-form-fieldองค์ประกอบหลังจากที่คุณอัปเกรด

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

10
"ดูเหมือนว่าคุณกำลังใช้ ngModel ในช่องฟอร์มเดียวกันกับ formControlName การสนับสนุนการใช้คุณสมบัติการป้อนข้อมูล ngModel และเหตุการณ์ ngModelChange ที่มีคำสั่งรูปแบบปฏิกิริยาถูกเลิกใช้แล้วใน Angular v6 และจะถูกลบออกใน Angular v7 สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ ดูเอกสาร API ของเราที่นี่: angular.io/api/forms/FormControlName#use-with-ngmodel "
ldgorman

1
@ldgorman - ฉันไม่เห็นว่าคุณกำลังสรุปว่าอย่างไร หากคุณกำลังอ้างถึงmat-form-fieldนี่..."used to wrap several Angular Material components and apply common Text field styles"ไม่ใช่สิ่งเดียวกัน อื่น ๆ กว่าที่ OP และคำตอบของฉันทำให้ไม่มีการเอ่ยถึงFormControl, หรือFormGroup FormControlName
อิกอร์

1
ฉันมีปัญหาเดียวกันแม้ว่าจะใช้โค้ดเดียวกันกับข้างบนแล้ว @Igor
Chuck

@Chuck - หากคุณยังคงมีปัญหาโปรดถามคำถามใหม่และมีตัวอย่างที่สามารถทำซ้ำได้น้อยที่สุด หากคุณต้องการให้ฉันดูคุณสามารถตอบกลับความคิดเห็นนี้พร้อมลิงก์ไปยังคำถามนั้น
Igor

2
@ Igor- เราคิดออกแล้วค่าจะถูกส่งกลับเป็นตัวเลขและเลือก Mat เพื่อค้นหาสตริง [compareWith]คำสั่งคือสิ่งที่เราใช้
Chuck

94

ใช้compareWithฟังก์ชันเพื่อเปรียบเทียบค่าตัวเลือกกับค่าที่เลือก ดูที่นี่: https://material.angular.io/components/select/api#MatSelect

สำหรับวัตถุของโครงสร้างต่อไปนี้:

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

กำหนดมาร์กอัปดังนี้:

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

และกำหนดฟังก์ชันการเปรียบเทียบดังนี้:

compareObjects(o1: any, o2: any): boolean {
  return o1.name === o2.name && o1.id === o2.id;
}

8
สมบูรณ์แบบเมื่อจัดการกับวัตถุไม่ใช่อาร์เรย์ธรรมดา ขอบคุณ.
Riaan van Zyl

25

ฉันใช้ Angular 5 และรูปแบบปฏิกิริยากับ mat-select และไม่สามารถรับโซลูชันข้างต้นเพื่อแสดงค่าเริ่มต้น

ฉันต้องเพิ่ม [CompareWith] เพื่อจัดการกับประเภทต่างๆที่ใช้ภายในองค์ประกอบ mat-select ภายในดูเหมือนว่า mat-select จะใช้อาร์เรย์เพื่อเก็บค่าที่เลือกไว้ ซึ่งมีแนวโน้มที่จะอนุญาตให้รหัสเดียวกันทำงานกับการเลือกหลายรายการได้หากเปิดโหมดนั้นไว้

Angular Select Control Doc

นี่คือวิธีแก้ปัญหาของฉัน:

ตัวสร้างฟอร์มเพื่อเริ่มต้นการควบคุมฟอร์ม:

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

จากนั้นใช้ฟังก์ชัน CompareWith กับส่วนประกอบของคุณ:

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

ถัดไปสร้างและส่งออกฟังก์ชัน defineId (ฉันต้องสร้างฟังก์ชันแบบสแตนด์อโลนเพื่อให้ mat-select ใช้งานได้):

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

สุดท้ายเพิ่มคุณสมบัติ CompareWith ให้กับ mat-select ของคุณ:

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

ขอบคุณมาก! มันเป็นเรื่องที่ซับซ้อนมากในการค้นหาสาเหตุ
Pax Beach

@ Heather92065 นี่เป็นทางออกเดียวที่ได้ผลสำหรับฉัน ฉันรู้สึกขอบคุณคุณมาก!
Latin Warrior

16

คุณควรจะผูกพันเป็น[value]ในmat-optionขณะที่ด้านล่าง

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

การสาธิตสด


นี้ทำงานได้อย่างสมบูรณ์ แนะนำให้ใช้ ngModel หรือ setValue () นี่เป็นวิธีที่ง่ายและสมบูรณ์แบบ
Rohit Parte

10

คุณสามารถใช้ฟังก์ชันเปรียบเทียบของคุณเองได้

[compareWith]="compareItems"

ดูdocuด้วย ดังนั้นรหัสที่สมบูรณ์จะมีลักษณะดังนี้:

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

และในไฟล์ typescript:

  compareItems(i1, i2) {
    return i1 && i2 && i1.id===i2.id;
  }

วิธีนี้ใช้ได้ผลสำหรับฉันและฉันคิดว่านี่เป็นวิธีที่ถูกต้องเป็นส่วนใหญ่ แต่หากรายการมีเพียงองค์ประกอบเดียวก็จะไม่ทำงาน ขอบคุณ
Code Kadiya

ข้อยกเว้นประเภทใดที่คุณได้รับจากองค์ประกอบเดียว เนื่องจากการเปรียบเทียบควรมีผลในกรณีที่มีi1หรือi2ไม่มีอยู่
LeO

6

ดังที่ได้กล่าวไปแล้วใน Angular 6 โดยใช้ ngModel ในรูปแบบปฏิกิริยานั้นเลิกใช้งานแล้ว (และลบออกใน Angular 7) ดังนั้นฉันจึงแก้ไขเทมเพลตและส่วนประกอบดังต่อไปนี้

แม่แบบ:

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

ส่วนหลักของส่วนประกอบ ( onChangesและรายละเอียดอื่น ๆ จะถูกละไว้):

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

หมายเหตุthis.filter.setValue (this.selected)ในngOnInitด้านบน

ดูเหมือนว่าจะทำงานใน Angular 6


นี่ควรเป็นคำตอบที่ดีที่สุดเนื่องจากยังครอบคลุมถึงการเลือกอ็อบเจ็กต์เมื่อจัดการกับผลลัพธ์ API สองรายการที่แตกต่างกันเพื่อเปรียบเทียบ
Marco Klein

(เช่นรายการทั้งหมดที่ต้องเลือกและรายการที่เลือกภายในการเรียก API อื่น)
Marco Klein

Angular 7 ยังคงใช้งานได้กับโมเดลที่ขับเคลื่อนด้วยเทมเพลต! แต่คุณไม่สามารถผสมกับรูปแบบปฏิกิริยาในเทมเพลตเดียวกันได้ คำใบ้ของคุณ[compareWith]เยี่ยมมาก
LeO

3

ฉันทำเหมือนในตัวอย่างเหล่านี้ พยายามกำหนดค่าของ mat-select เป็นค่าของ mat-option ตัวใดตัวหนึ่ง แต่ล้มเหลว.

ความผิดพลาดของฉันคือทำ [(value)] = "someNumberVariable" กับตัวแปรประเภทตัวเลขในขณะที่ตัวแปรใน mat-option เป็นสตริง แม้ว่าเทมเพลตจะดูเหมือนกัน แต่ก็ไม่ได้เลือกตัวเลือกนั้น

เมื่อฉันแยกวิเคราะห์ someNumberVariable เป็นสตริงทุกอย่างเรียบร้อยดี

ดังนั้นดูเหมือนว่าคุณต้องมี mat-select และค่า mat-option ไม่เพียง แต่เป็นตัวเลขเดียวกันเท่านั้น (หากคุณกำลังนำเสนอตัวเลข) แต่ยังต้องให้เป็นสตริงประเภทด้วย


นั่นเป็นปัญหาของฉันเช่นกัน อันหนึ่งเป็นตัวเลขอีกอันคือสตริง
Vadim Berman

2

ทางออกสำหรับฉันคือ:

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


});

การใช้ออบเจ็กต์: {id: number, detalle: string}


1

ลองดูสิ!

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

1

วิธีแก้ปัญหาของฉันค่อนข้างยุ่งยากและง่ายกว่า

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

ฉันเพียงแค่ทำให้การใช้งานของตัวยึด light grayสีเริ่มต้นของตัวยึดวัสดุ เพื่อให้ดูเหมือนว่ามีการเลือกตัวเลือกฉันเพียงแค่ปรับแต่ง CSS ดังนี้:

::ng-deep .mat-select-placeholder {
    color: black;
}

1

มีผลผูกพันหรือการตั้งค่าเริ่มต้นของการทำงานเฉพาะในกรณีที่ค่าแอตทริบิวต์ในMatSelectก็เปรียบได้กับค่าแอตทริบิวต์ binded เพื่อMatOption ถ้าคุณผูกcaptionของรายการของคุณเพื่อค่าแอตทริบิวต์ของเสื่อตัวเลือกองค์ประกอบที่คุณต้องตั้งค่าองค์ประกอบเริ่มต้นบนเสื่อเลือกไปcaptionของรายการของคุณมากเกินไป หากคุณผูกIdรายการของคุณกับmat-optionคุณต้องผูกidกับmat-selectด้วยไม่ใช่ทั้งรายการคำอธิบายภาพหรืออื่น ๆ เพียงช่องเดียวกัน

แต่คุณต้องทำด้วยการผูก []


1

ฉันทำตามข้างต้นอย่างระมัดระวังและยังไม่สามารถรับค่าเริ่มต้นที่เลือกได้

เหตุผลก็คือแม้ว่าค่าที่ผูกไว้ของฉันจะถูกกำหนดเป็นสตริงใน typescript แต่ API แบ็กเอนด์ของฉันก็ส่งคืนตัวเลข

การพิมพ์ Javascript หลวมเพียงแค่เปลี่ยนประเภทที่รันไทม์ (โดยไม่มีข้อผิดพลาด) ซึ่งป้องกันไม่ให้เลือกค่าเริ่มต้น

ส่วนประกอบ

myBoundValue: string;

เทมเพลต

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

วิธีแก้ไขคือการอัปเดต API เพื่อส่งคืนค่าสตริง


1

วิธีที่ง่ายมากในการบรรลุเป้าหมายนี้คือการใช้ a ที่formControlมีค่าเริ่มต้นภายใน a FormGroup(ไม่บังคับ) เช่น นี่คือตัวอย่างการใช้ตัวเลือกหน่วยสำหรับอินพุตพื้นที่:

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>

0

การเปรียบเทียบระหว่างตัวเลขและสตริงใช้เป็นเท็จดังนั้นให้โยนค่าที่คุณเลือกไปยังสตริงภายใน ngOnInit และจะได้ผล

ฉันมีปัญหาเดียวกันฉันกรอก mat-select ด้วย enum โดยใช้

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

และฉันมีค่า enum ที่ฉันต้องการเลือก ...

ฉันใช้เวลาไม่กี่ชั่วโมงในการดิ้นรนเพื่อหาสาเหตุว่าทำไมมันถึงไม่ได้ผล และฉันทำหลังจากแสดงผลตัวแปรทั้งหมดที่ใช้ใน mat-select คอลเลคชันคีย์และที่เลือก ... ถ้าคุณมี ["0", "1", "2"] และคุณต้องการเลือก 1 ( ซึ่งเป็นตัวเลข) 1 == "1" เป็นเท็จและด้วยเหตุนี้จึงไม่มีการเลือก

ดังนั้นวิธีแก้ปัญหาคือการส่งค่าที่คุณเลือกไปยังสตริงภายใน ngOnInit และมันจะทำงาน


1
สวัสดีฮวนคุณอาจต้องการดูโพสต์นี้ซึ่งจะลงรายละเอียดเกี่ยวกับตัวดำเนินการความเท่าเทียมกันใน JS: stackoverflow.com/questions/359494/…
William Moore

สวัสดีวิลเลียมนั่นเป็นโพสต์ที่ยอดเยี่ยมฉันเคยไปที่นั่นสองสามครั้ง ... และฉันได้เรียนรู้วิธีเปรียบเทียบอย่างถูกต้อง (ฉันหวังว่าและฉันจะสามารถตรวจสอบเอกสารได้ตลอดเวลา) ... ปัญหาที่นี่คือการผูกที่บังคับโดย ตัวควบคุมวัสดุซึ่งใช้ประเภทจำนวนและสตริงต่างกัน ... ตัวควบคุมนั้นคาดว่าจะมีประเภทเดียวกันดังนั้นหากเลือกเป็นตัวเลขคอลเลกชันจะต้องเป็นชุดของตัวเลข ... นั่นคือปัญหา
Juan

0

ฉันทำอย่างนี้.

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

โดยปกติคุณสามารถทำได้[value]="option"เว้นแต่คุณจะได้รับตัวเลือกจากฐานข้อมูลบางส่วน ?? ฉันคิดว่าความล่าช้าในการรับข้อมูลทำให้ไม่ทำงานหรือวัตถุที่ได้รับมีความแตกต่างกันบ้างแม้ว่าจะเหมือนกัน ?? น่าแปลกที่จะเป็นไปได้มากที่สุดในภายหลังเนื่องจากฉันลอง[value]="option === selected ? selected : option"แล้ว แต่ก็ไม่ได้ผล


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>

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>


สิ่งนี้จะช่วยได้เมื่อคุณใช้ Edit & Update ในองค์ประกอบที่ปลอดภัย
lilandos didas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.