Vật liệu góc cạnh: mat-select không chọn mặc định


109

Tôi có một mat-select trong đó các tùy chọn là tất cả các đối tượng được xác định trong một mảng. Tôi đang cố gắng đặt giá trị thành mặc định cho một trong các tùy chọn, tuy nhiên, nó vẫn được chọn khi trang hiển thị.

Tệp chỉ định của tôi chứa:

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

Tệp HTML của tôi chứa:

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

Tôi đã cố gắng thiết lập selected2valuetrong mat-optioncả các đối tượng và nó id, và đã cố gắng sử dụng cả hai [(value)][(ngModel)]trong mat-select, nhưng không ai đang làm việc.

Tôi đang sử dụng material phiên bản 2.0.0-beta.10


2
Sử dụng compareWith. Nó thanh lịch hơn.
Badis Merabet

PHẢI CÓ compareWith, xem Badis trả lời ở đây stackoverflow.com/questions/47333171/...
bresleveloper

Câu trả lời:


144

Sử dụng một ràng buộc cho giá trị trong mẫu của bạn.

value="{{ option.id }}"

nên là

[value]="option.id"

Và trong giá trị đã chọn của bạn sử dụng ngModelthay vì value.

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

nên là

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

Hoàn thành mã:

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

Một lưu ý nhỏ là kể từ phiên bản 2.0.0-beta.12 , lựa chọn vật liệu hiện chấp nhận một mat-form-fieldphần tử làm phần tử mẹ để nó nhất quán với các kiểm soát đầu vào vật liệu khác. Thay thế divphần tử bằng mat-form-fieldphần tử sau khi bạn nâng cấp.

<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
"Có vẻ như bạn đang sử dụng ngModel trên cùng một trường biểu mẫu với formControlName. Hỗ trợ sử dụng thuộc tính đầu vào ngModel và sự kiện ngModelChange với các lệnh biểu mẫu phản ứng đã không được chấp nhận trong Angular v6 và sẽ bị xóa trong Angular v7. Để biết thêm thông tin về điều này , xem tài liệu API của chúng tôi tại đây: angle.io/api/forms/FormControlName#use-with-ngmodel "
ldgorman,

1
@ldgorman - Tôi không hiểu bạn rút ra kết luận như thế nào. Nếu bạn đang đề cập đến mat-form-field, đây là ..."used to wrap several Angular Material components and apply common Text field styles", vì vậy không phải là điều tương tự. Ngoài ra OP và cũng trả lời của tôi đã không đề cập đến FormControl, FormGrouphoặc FormControlName.
Igor

1
Tôi đang gặp vấn đề tương tự ngay cả sau khi triển khai mã tương tự như trên @Igor
Chuck

@Chuck - Nếu bạn vẫn gặp sự cố, vui lòng đặt một câu hỏi mới và bao gồm một ví dụ có thể tái tạo tối thiểu . Nếu bạn muốn tôi xem xét, bạn có thể trả lời nhận xét này với một liên kết đến câu hỏi đó.
Igor

2
@ Igor- Chúng tôi đã tìm ra, giá trị đang được trả về dưới dạng số và Mat-chọn nó đang tìm kiếm một chuỗi. [compareWith]Chỉ là những gì chúng tôi sử dụng
Chuck

94

Sử dụng compareWith, Một hàm để so sánh các giá trị tùy chọn với các giá trị đã chọn. xem tại đây: https://material.angular.io/components/select/api#MatSelect

Đối với một đối tượng của cấu trúc sau:

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

Xác định đánh dấu như sau:

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

Và xác định hàm so sánh như thế này:

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

8
Hoàn hảo khi xử lý các đối tượng chứ không phải mảng đơn giản. Cảm ơn bạn.
Riaan van Zyl

25

Tôi đang sử dụng Angular 5 và các biểu mẫu phản ứng với mat-select và không thể nhận được một trong các giải pháp trên để hiển thị giá trị ban đầu.

Tôi đã phải thêm [so sánh với] để xử lý các kiểu khác nhau đang được sử dụng trong thành phần mat-select. Bên trong, có vẻ như mat-select sử dụng một mảng để giữ giá trị đã chọn. Điều này có thể cho phép cùng một mã hoạt động với nhiều lựa chọn nếu chế độ đó được bật.

Angular Select Control Doc

Đây là giải pháp của tôi:

Trình tạo biểu mẫu để khởi tạo điều khiển biểu mẫu:

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

Sau đó, triển khai hàm CompareWith trên thành phần của bạn:

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

Tiếp theo, tạo và xuất hàm xác định (tôi phải tạo một hàm độc lập để mat-select có thể sử dụng nó):

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

Cuối cùng thêm thuộc tính CompareWith vào mat-select của bạn:

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

Cảm ơn rất nhiều! Rất khó tìm ra nguyên nhân.
Bãi biển Pax

@ Heather92065 Đây là giải pháp duy nhất phù hợp với tôi. Tôi rất biết ơn bạn!
Chiến binh Latinh

16

Bạn nên ràng buộc nó như [value]trong phần mat-optiondưới đây,

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

BẢN THỬ TRỰC TIẾP


Điều này hoạt động hoàn hảo. Insted của việc sử dụng ngModel hoặc setValue () đây là phương pháp đơn giản nhất và hoàn hảo
Rohit Parte

10

Bạn chỉ có thể triển khai chức năng so sánh của riêng mình

[compareWith]="compareItems"

Xem cả tài liệu . Vì vậy, mã hoàn chỉnh sẽ giống như sau:

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

và trong tệp Typecript:

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

Điều này phù hợp với tôi và tôi nghĩ đây là cách chính xác nhất nhưng nếu danh sách chỉ chứa một phần tử thì nó không hoạt động. Cảm ơn
Mã Kadiya

Loại ngoại lệ nào bạn nhận được chỉ với một phần tử? Vì so sánh sẽ được tính nếu có i1hoặc i2không tồn tại.
LeO

6

Như đã đề cập trong Angular 6, sử dụng ngModel trong các biểu mẫu phản ứng không được dùng nữa (và bị loại bỏ trong Angular 7), vì vậy tôi đã sửa đổi mẫu và thành phần như sau.

Bản mẫu:

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

Các phần chính của thành phần ( onChangesvà các chi tiết khác được bỏ qua):

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

Lưu ý this.filter.setValue (this.selected)ngOnInittrên.

Nó dường như hoạt động trong Angular 6.


Đây thực sự phải là câu trả lời tốt nhất, vì điều này cũng bao gồm các lựa chọn đối tượng khi xử lý hai kết quả API khác nhau để so sánh.
Marco Klein

(ví dụ: Tổng danh sách các mục để chọn và mục đã chọn trong lệnh gọi api khác).
Marco Klein

Angular 7 vẫn hoạt động với các mô hình điều khiển theo khuôn mẫu! Nhưng bạn không thể trộn nó với các dạng phản ứng trên cùng một khuôn mẫu. Gợi ý của bạn với cái [compareWith]thật tuyệt
LeO

3

Tôi đã làm nó giống như trong các ví dụ này. Đã cố gắng đặt giá trị của mat-select thành giá trị của một trong các mat-options. Nhưng không thành công.

Sai lầm của tôi là đã thực hiện [(value)] = "someNumberVariable" với một biến kiểu số trong khi những biến trong tùy chọn mat là chuỗi. Ngay cả khi chúng trông giống nhau trong mẫu, nó sẽ không chọn tùy chọn đó.

Sau khi tôi phân tích cú pháp someNumberVariable thành một chuỗi, mọi thứ hoàn toàn ổn.

Vì vậy, có vẻ như bạn cần có mat-select và các giá trị mat-option không chỉ là cùng một số (nếu bạn đang trình bày số) mà còn để chúng có kiểu chuỗi.


Đó cũng là vấn đề của tôi. Một là số, một là chuỗi.
Vadim Berman

2

Giải pháp cho tôi là:

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


});

Sử dụng đối tượng: {id: number, detalle: string}


1

Thử cái này!

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

Giải pháp của tôi là một chút phức tạp và đơn giản hơn.

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

Tôi chỉ sử dụng trình giữ chỗ . Màu mặc định của vật liệu giữ chỗ là light gray. Để làm cho nó trông giống như tùy chọn đã được chọn, tôi chỉ cần thao tác CSS như sau:

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

1

Ràng buộc hoặc cài đặt giá trị mặc định chỉ hoạt động nếu thuộc tính giá trị trên MatSelect có thể so sánh với thuộc tính giá trị được liên kết với MatOption . Nếu bạn liên kết captionmặt hàng của mình với thuộc tính value của phần tử mat-option, bạn cũng phải đặt phần tử mặc định trên mat-select thành captioncủa mặt hàng. Nếu bạn liên kết Idmục của mình với mat-option , bạn cũng phải liên kết idvới mat-select , không phải toàn bộ mục, chú thích hay bất kỳ thứ gì khác, chỉ cùng một trường.

Nhưng bạn cần làm điều đó với ràng buộc []


1

Tôi đã làm theo những điều trên rất cẩn thận và vẫn không thể chọn được giá trị ban đầu.

Lý do là mặc dù giá trị bị ràng buộc của tôi được xác định là một chuỗi trong tập lệnh, nhưng API phụ trợ của tôi đang trả về một số.

Việc nhập lỏng trong Javascript chỉ đơn giản là thay đổi kiểu trong thời gian chạy (không có lỗi), điều này đã ngăn cản việc chọn giá trị ban đầu.

Thành phần

myBoundValue: string;

Bản mẫu

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

Giải pháp là cập nhật API để trả về một giá trị chuỗi.


1

Một cách rất đơn giản để đạt được điều này là sử dụng một formControlgiá trị mặc định, bên trong một FormGroup(tùy chọn) chẳng hạn. Đây là một ví dụ sử dụng bộ chọn đơn vị cho đầu vào khu vực:

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

So sánh giữa một số và một chuỗi được sử dụng là false , vì vậy, hãy chuyển giá trị bạn đã chọn sang một chuỗi trong ngOnInit và nó sẽ hoạt động.

Tôi đã gặp vấn đề tương tự, tôi đã điền vào mat-select bằng một enum, sử dụng

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

và tôi đã có giá trị enum mà tôi muốn chọn ...

Tôi đã dành vài giờ đấu tranh tâm trí của mình để cố gắng xác định tại sao nó không hoạt động. Và tôi đã làm điều đó ngay sau khi hiển thị tất cả các biến đang được sử dụng trong mat-select, bộ sưu tập khóa và lựa chọn ... nếu bạn có ["0", "1", "2"] và bạn muốn chọn 1 ( là một số) 1 == "1" là sai và do đó không có gì được chọn.

vì vậy, giải pháptruyền giá trị bạn đã chọn sang một chuỗi bên trong ngOnInit và nó sẽ hoạt động.


1
Xin chào Juan, bạn có thể muốn xem bài đăng này đi vào chi tiết về các toán tử bình đẳng khác nhau trong JS: stackoverflow.com/questions/359494/…
William Moore

Xin chào William, đó là một bài viết tuyệt vời, tôi đã đến đó vài lần ... Và tôi đã học được cách so sánh đúng cách (tôi hy vọng và tôi luôn có thể xem lại tài liệu) ... Vấn đề ở đây là các ràng buộc, bị ép buộc bởi bộ điều khiển vật liệu, nơi sử dụng các loại, số và chuỗi khác nhau ... Bộ điều khiển đó mong đợi có các loại giống nhau, vì vậy, nếu được chọn là một số, tập hợp phải là tập hợp các số ... Đó là vấn đề.
Juan

0

Tôi đã làm điều này.

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

Thông thường bạn có thể làm được [value]="option", trừ khi bạn nhận được các tùy chọn của mình từ một số cơ sở dữ liệu ?? Tôi nghĩ rằng hoặc sự chậm trễ của việc nhận dữ liệu khiến nó không hoạt động hoặc các đối tượng nhận được khác nhau theo một cách nào đó mặc dù chúng giống nhau ?? Thật kỳ lạ, nó rất có thể là cái muộn hơn, vì tôi cũng đã thử [value]="option === selected ? selected : option"nhưng nó không hoạt động.


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>


Điều này sẽ hữu ích khi bạn đang sử dụng Chỉnh sửa & Cập nhật trong thành phần an toàn,
lilandos didas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.