【问题标题】: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

【问题讨论】:

标签: angular typescript angular-material2


【解决方案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 中不同的相等运算符:stackoverflow.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>
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-02-17
                      • 1970-01-01
                      • 2020-07-05
                      • 1970-01-01
                      • 2019-03-11
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-05-19
                      • 1970-01-01
                      相关资源
                      最近更新 更多