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

Posted

技术标签:

【中文标题】角材料:垫选择不选择默认【英文标题】:Angular Material: mat-select not selecting default 【发布时间】:2018-04-30 04:46:20 【问题描述】:

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

我尝试将selected2mat-option 中的value 设置为对象和它的ID,并尝试在mat-select 中同时使用[(value)][(ngModel)],但都没有工作。

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

【问题讨论】:

使用compareWith。它更优雅。 必须有compareWith,在此处查看badis 答案***.com/questions/47333171/… 【参考方案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>

从version 2.0.0-beta.12 开始,material 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>

【讨论】:

"看起来您在与 formControlName 相同的表单字段上使用 ngModel。Angular v6 中已弃用支持使用 ngModel 输入属性和 ngModelChange 事件与反应式表单指令,并将在Angular v7。有关这方面的更多信息,请在此处查看我们的 API 文档:angular.io/api/forms/FormControlName#use-with-ngmodel" @ldgorman - 我不明白你是如何得出这个结论的。如果您指的是mat-form-field,这是..."used to wrap several Angular Material components and apply common Text field styles",所以不是一回事。除此之外,OP 和我的回答都没有提到 FormControlFormGroupFormControlName 即使在实现了与上述@Igor 相同的代码后,我也遇到了同样的问题 @Igor- 我们想通了,该值作为一个数字返回,而 Mat-select 它正在寻找一个字符串。 [compareWith] 指令是我们使用的 支持使用 ngModel 输入属性和带有响应式表单指令的 ngModelChange 事件已在 Angular v6 中弃用,并将在 Angular v7 中删除。这个答案不再起作用了。请将其定义为最大支持到 v6 或删除【参考方案2】:

您应该在mat-option 中将其绑定为[value],如下所示,

<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

【讨论】:

这非常有效。使用 ngModel 或 setValue() 这是最简单和完美的方法【参考方案3】:

我正在使用 Angular 5 和带有 mat-select 的反应形式,并且无法获得上述任何一种解决方案来显示初始值。

我必须添加 [compareWith] 来处理 mat-select 组件中使用的不同类型。在内部,mat-select 似乎使用一个数组来保存选定的值。如果打开该模式,这可能允许相同的代码处理多个选择。

Angular Select Control Doc

这是我的解决方案:

Form Builder 初始化表单控件:

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;

接下来创建并导出determineId函数(我必须创建一个独立函数以便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>

【讨论】:

非常感谢!很难找到原因。 @Heather92065 这是唯一对我有用的解决方案。非常感谢你! @Heather92065 如果要比较的键值是 Input() 值,这将如何工作?我的场景是我有一个可重用的组件,它需要知道提取值是什么才能显示它。比较函数在此值有效之前运行。你如何解决这个问题?【参考方案4】:

使用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;

【讨论】:

在处理对象而不是简单数组时非常完美。谢谢。【参考方案5】:

试试这个!

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

【讨论】:

【参考方案6】:

我的解决方案有点棘手和简单。

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

【讨论】:

【参考方案7】:

正如 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;

注意上面ngOnInit中的this.filter.setValue(this.selected)

它似乎在 Angular 6 中工作。

【讨论】:

这实际上应该是最好的答案,因为这也涵盖了在处理要比较的两个不同 API 结果时的对象选择。 (例如,要从中选择的项目的总列表以及在另一个 api 调用中选择的项目)。 Angular 7 仍然适用于模板驱动模型!但是你不能将它与同一个模板上的反应形式混合。您对[compareWith] 的提示很棒【参考方案8】:

我的解决方案是:

<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

【讨论】:

【参考方案9】:

您可以简单地实现自己的比较功能

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

【讨论】:

这对我有用,我认为这主要是正确的方法,但如果列表只包含一个元素,它就不起作用。谢谢 只有一个元素会出现什么样的异常?因为如果 i1i2 不存在,比较应该负责。【参考方案10】:

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

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

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

所以看起来你需要让 mat-select 和 mat-option 值不仅是相同的数字(如果你正在呈现数字),而且还要让它们是字符串类型。

【讨论】:

这也是我的问题。一个是数字,另一个是字符串。【参考方案11】:

数字和字符串之间的比较通常为假,因此,将您选择的值转换为 ngOnInit 中的字符串即可。

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

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

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

我花了几个小时在脑海中挣扎,试图找出它不起作用的原因。我只是在渲染了 mat-select 中使用的所有变量、键集合和选定的...如果你有 ["0","1","2"] 并且你想选择 1 (这是一个数字)1=="1" 为假,因此没有选择任何内容。

所以,解决方案将您选择的值转换为 ngOnInit 中的字符串,它会起作用。

【讨论】:

嗨,Juan,你可能想看看这篇文章,其中详细介绍了 JS 中不同的相等运算符:***.com/questions/359494/… 嗨威廉,这是一个很棒的帖子,我去过那里几次......我学会了如何正确比较(我希望,我总是可以查看文档)......问题这里是绑定,由材质控制器强制使用不同的类型、数字和字符串...该控制器期望具有相同的类型,因此,如果选择的是数字,则集合必须是数字的集合...这就是问题所在。【参考方案12】:

仅当 MatSelect 上的 value 属性与绑定到 MatOptionvalue 属性相当时,默认值的绑定或设置才有效/强>。如果您将项目的caption 绑定到 ma​​t-option 元素的 value 属性,则必须将 ma​​t-select 上的默认元素设置为 @ 987654322@ 您的商品也是如此。如果您将项目的Id 绑定到ma​​t-option,您也必须将id 绑定到ma​​t-select,而不是整个项目、标题或任何其他,只有同一个字段。

但你需要通过绑定[]来做到这一点

【讨论】:

【参考方案13】:

我这样做了。

<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",但没有成功。

【讨论】:

【参考方案14】:

我非常仔细地按照上面的操作,仍然无法选择初始值。

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

javascript 松散类型只是在运行时更改类型(没有错误),这会阻止选择初始值。

组件

myBoundValue: string;

模板

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

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

【讨论】:

【参考方案15】:

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

【讨论】:

【参考方案16】:

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>

【讨论】:

【参考方案17】:

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>

【讨论】:

这将有助于您在安全组件中使用编辑和更新,【参考方案18】:

在使用角度材质选择时,最好使用 compareWith 函数来比较您的对象。 如果您想了解有关如何使用 mat-select 的更多信息,可以查看以下链接: The importance of the compare function in angular material select

【讨论】:

【参考方案19】:

页面加载时,我在绑定第一个选项时遇到问题。下面有帮助我的解决方案

.html

<mat-form-field appearance="outline">    
    <mat-select #teamDropdown 
        [ngModel]="selectedGroupId" (selectionChange)="selectedGroupId=$event.value">
        <mat-option value=undefined>Please Select</mat-option>
        <mat-option *ngFor="let grp of groups" [value]="grp.groupsId">
            grp.groupName
        </mat-option>
    </mat-select>
</mat-form-field>

.ts

@ViewChild('teamDropdown') teamDropdown: MatSelect;
ngAfterViewInit() 
    setTimeout(() => 
        this.teamDropdown.options.first.select();
    );

【讨论】:

你的意思是:this.teamDropdown .options.first.select();【参考方案20】:

唯一的解决方案是你的表单控件或 Ng Model 值在 mat select 标记中必须与分配给选项标记中的值的文本匹配 这是 ts文件

selectedFood = 'Tacos';

模板

    <mat-form-field appearance="fill">
      <mat-label>Favorite Food</mat-label>
      <mat-select [(value)]="selectedFood">
        <mat-option value=''>---------</mat-option>
<mat-option value='Tacos'>Tacos</mat-option>
<mat-option value='Pizza'>Pizza</mat-option>
        
      </mat-select>
    </mat-form-field>
    <p>You selected: selectedFood</p>

【讨论】:

以上是关于角材料:垫选择不选择默认的主要内容,如果未能解决你的问题,请参考以下文章

清除垫选择选择角材料

如何防止角材料垫菜单关闭?

角材料更改垫复选框内的刻度颜色

角材料步进器在选择更改之前并防止在某些条件下进行步进更改

角材料垫按钮不会更新外部指令的禁用更改

可重复使用的角材料垫表