Angular Материал: мат-выберите не выбрать значение по умолчанию

У меня есть mat-select, где в качестве параметров указаны все объекты, определенные в массиве. Я пытаюсь установить значение по умолчанию для одного из параметров, однако оно остается выбранным при отображении страницы.

Мой машинописный файл содержит:

  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-бета .10

Ответ 1

Используйте привязку для значения в вашем шаблоне.

value="{{ option.id }}"

должен быть

[value]="option.id"

И в выбранном вами значении используйте ngModel вместо value.

<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 select > теперь принимает элемент 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>

Ответ 2

Используйте compareWith, A для сравнения значений параметров с выбранными значениями. см. здесь: 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;
}

Ответ 3

Я использую 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 ] ),
    ...
});

Затем реализуйте функцию сравнения с вашим компонентом:

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>

Ответ 4

Вы должны привязать его как [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>

LIVE DEMO

Ответ 5

Как уже упоминалось в 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.

Ответ 6

Вы можете просто реализовать свою собственную функцию сравнения

[compareWith]="compareItems"

Смотрите также документ. Таким образом, полный код будет выглядеть так:

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

Ответ 7

Я сделал это так же, как в этих примерах. Пытался установить значение mat-select равным значению одной из опций mat. Но не удалось.

Моя ошибка заключалась в том, чтобы сделать [(value)] = "someNumberVariable" для переменной числового типа, в то время как переменные в mat-options были строками. Даже если они выглядят одинаково в шаблоне, он не выберет эту опцию.

Как только я проанализировал строку someNumberVariable, все было в порядке.

Поэтому, похоже, вам нужно, чтобы значения mat-select и mat-option не только были одинаковыми (если вы представляете числа), но и позволяли им иметь тип string.

Ответ 8

Мое решение немного сложнее и проще.

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

Ответ 9

Решение для меня было:

<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: номер, detalle: строка}

Ответ 10

Попробуй это!

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

Ответ 11

ОТВЕТ НА УГЛОВОЙ V6 и UP

Поддержка использования входных свойств ngModel и события ngModelChange с директивами формы реактивного и управляемого шаблонами устарела в Angular v6 и будет удалена в Angular v7.

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

Ответ 12

Сравнение между числом и строкой использует значение false, поэтому приведите выбранное вами значение к строке внутри ngOnInit, и она будет работать.

У меня возникла та же проблема, я заполнил mat-select перечислением, используя

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

и у меня было значение enum, которое я хотел выбрать...

Я потратил несколько часов, пытаясь понять, почему это не работает. И я сделал это сразу после рендеринга всех переменных, используемых в mat-select, коллекции ключей и selected... если у вас есть ["0", "1", "2"] и вы хотите выбрать 1 ( который является числом) 1 == "1" является ложным, и поэтому ничего не выбрано.

Итак, решение состоит в том, чтобы преобразовать выбранное вами значение в строку внутри ngOnInit, и это будет работать.