角材料:垫选择不选择默认


108

我有一个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>

我曾尝试设置selected2valuemat-option给该对象和它的ID,并使用都不断地尝试[(value)][(ngModel)]mat-select,但没有正常工作。

我正在使用材料版本2.0.0-beta.10


2
使用compareWith。更优雅。
Badis Merabet

必须compareWith,请在这里查看badis的答案stackoverflow.com/questions/47333171/…–
bresleveloper

Answers:


144

对模板中的值使用绑定。

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材料选择现在接受mat-form-field元素作为父元素因此它与其他材料输入控件是一致的。升级后,divmat-form-fieldelement 替换element 。

<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
“看来您在与formControlName相同的表单字段上使用ngModel。在Angular v6中已弃用对ngModel input属性和ngModelChange事件与反应式表单指令一起使用的支持,并将在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,也是我的回答没有提到FormControlFormGroupFormControlName
伊戈尔(Igor)'18

1
即使实现与上述@Igor相同的代码,我也遇到同样的问题
Chuck

@Chuck-如果仍然遇到问题,请提出一个新问题,并提供一个最小的可复制示例。如果您希望我看看,可以回复此评论,并提供指向该问题的链接。
伊戈尔(Igor)

2
@ Igor-我们弄清楚了,该值以数字形式返回,然后用Mat进行选择以寻找字符串。[compareWith]指令就是我们使用的指令
Chuck

92

使用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使用数组保存选定的值。如果打开该模式,则可能允许同一代码与多个选择一起使用。

角度选择控制文档

这是我的解决方案:

表单生成器初始化表单控件:

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-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这是唯一对我有用的解决方案。我非常感谢你!
拉丁勇士

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"

另请参阅文档。因此完整的代码如下所示:

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

这对我来说是有效的,我认为这基本上是正确的方法,但是如果list仅包含一个元素,则它不起作用。谢谢
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结果进行比较时,这也涵盖了对象选择。
马可·克莱因

(例如,要从中选择的项的总列表以及在另一个api调用中选择的项)。
马可·克莱因

Angular 7仍适用于模板驱动模型!但是,您不能将其与同一模板上的反应式形式混合使用。您的提示[compareWith]非常棒
LeO

3

就像在这些示例中一样,我做到了。试图将mat-select的值设置为mat-options之一的值。但是失败了。

我的错误是将[(value)] =“ someNumberVariable”用作数字类型变量,而mat-options中的变量则是字符串。即使它们在模板中看起来相同,也不会选择该选项。

一旦我将someNumberVariable解析为字符串,一切就很好了。

因此看来,您不仅需要使mat-select和mat-option值具有相同的数字(如果您要提供数字),还需要使它们的类型为string。


那也是我的问题。一个是数字,另一个是字符串。
瓦迪姆·伯曼

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:数字,细节:字符串}


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媲美绑定到属性MatOption。如果您绑定caption您的物品到的属性垫选项必须设置默认元素元素垫选择caption您的产品了。如果将Id项目绑定到mat-option,也必须也绑定idmat-select,而不是整个项目,标题或任何其他项目,而只能绑定到同一字段。

但是您需要使用绑定[]


1

我非常仔细地遵循了上述内容,但仍然无法获得所选的初始值。

原因是,尽管我的绑定值在打字稿中定义为字符串,但我的后端API返回了一个数字。

Javascript松散类型只是在运行时更改了类型(没有错误),从而阻止了对初始值的选择。

零件

myBoundValue: string;

模板

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

解决方案是更新API以返回字符串值。


1

实现此目的的一种非常简单的方法是使用formControl带有默认值的,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

数字和字符串之间的比较用于false,因此,将您选择的值强制转换为ngOnInit中的字符串,它将起作用。

我有同样的问题,我用枚举填充了mat-select,使用

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

我有想要选择的枚举值...

我花了几个小时苦苦挣扎,试图找出为什么它不起作用。在渲染了mat-select,keys集合和selected中使用的所有变量之后,我就这样做了。如果您有[“ 0”,“ 1”,“ 2”],并且想要选择1(这是一个数字)1 ==“ 1”为假,因此未选择任何内容。

因此,解决方案将您选择的值强制转换为ngOnInit中的字符串,它将起作用。


1
喜娟,你可能想看看这个帖子里面介绍了有关不同平等运营商在JS的细节:stackoverflow.com/questions/359494/...
威廉·穆尔

嗨,威廉,你好,我去过那里好几次了……我学会了如何正确比较(我希望,我总能审阅文档)……这里的问题是,由物料控制器,其中使用不同的类型,数字和字符串...该控制器希望具有相同的类型,因此,如果选择的是数字,则该集合必须是数字的集合...这就是问题所在。
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>


当您在安全组件中使用“编辑和更新”时,这将有所帮助
lilandos didas,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.