Angular Material Select - 默认值 - Reactive Forms [英] Angular Material Select - Default Value - Reactive Forms

查看:28
本文介绍了Angular Material Select - 默认值 - Reactive Forms的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里失去了它.关于这个主题的问题太多了,无论我怎么尝试都无法解决.

我只是想设置 mat-select 的默认值.

我有一份员工名单.单击列表项会打开一个对话框(员工详细信息),以便我可以编辑(或添加)员工的数据.我只是想让部门垫选择在模式为编辑时显示员工的当前部门.

employee-details.component.html

<div class="flex-item" fxFlex mat-dialog-actions fxLayoutAlign="end"><button mat-mini-fab color="" aria-label="Cancel" (click)="onCancelClick()"><mat-icon>clear</mat-icon>

<h4 *ngIf="data.action == 'add'">添加新员工</h4><h4 *ngIf="data.action == 'edit'">编辑员工</h4><form [formGroup]="form" class="employee-form"><div class="form-group"><mat-form-field class="employee-full-width"><输入表单控件名称=名字"垫输入必需的占位符=员工名字"><mat-error*ngIf="form.get('firstname').touched &&form.get('firstname').invalid">员工名字是必需的!</mat-error></mat-form-field><mat-form-field class="employee-full-width"><输入formControlName="姓氏"垫输入必需的占位符="员工姓氏"><mat-error*ngIf="form.get('lastname').touched &&form.get('lastname').invalid">员工姓氏为必填项!</mat-error></mat-form-field><mat-form-field class="employee-full-width"><输入表单控件名称=标题"垫输入必需的占位符=员工职称"><mat-error*ngIf="form.get('title').touched &&form.get('title').invalid">员工职称是必填项!</mat-error></mat-form-field><mat-form-field class="employee-full-width"><输入表单控件名称=比率"垫输入必需的占位符=员工率"><mat-error*ngIf="form.get('rate').touched &&form.get('rate').invalid">员工率是必需的!</mat-error></mat-form-field><mat-form-field class="employee-full-width"><mat-label>部门</mat-label><mat-select formControlName="部门"><mat-option *ngFor="let dept of Department" [value]="dept">{{ 部门?.title }}</mat-option></mat-select></mat-form-field>

</表单><div class="flex-item" fxFlex mat-dialog-actions fxLayoutAlign="end"><按钮垫高按钮颜色=次要"类=项目添加按钮"(点击)=onNoClick()">取消<按钮垫高按钮[禁用]="!form.valid"颜色=主要"类=项目添加按钮"(点击)=创建员工(表单)">保存&关闭<按钮垫高按钮[禁用]="!form.valid"颜色=主要"类=项目添加按钮"(点击)=创建员工(表单)">保存&新的

<div><div><br/><br/><垫手风琴><垫子扩展面板><mat-expansion-panel-header><mat-panel-title>表单值</mat-panel-title></mat-expansion-panel-header><代码><div fxLayout="column" fxLayoutGap="32px"><div>{{ form.value |json }}</div><div>表单有效性:{{ form.valid |json}}</div>

</mat-expansion-panel></mat-accordion>

employee-details.component.ts

import { Component, OnInit, Optional, Inject, AfterViewInit } from '@angular/core';从@angular/forms"导入 { FormGroup, FormControl, Validators };从'src/app/core/services/entity/employee.service'导入{EmployeeService};从'@angular/material' 导入 { MatDialogRef, MAT_DIALOG_DATA };从'src/app/employees/employee-list/employee-list.component'导入{DialogData};从'src/app/core/services/entity/department.service'导入{部门服务};从src/app/shared/models/department"导入{部门};@成分({选择器:'app-employee-details',templateUrl: './employee-details.component.html',styleUrls: ['./employee-details.component.css']})导出类 EmployeeDetailsComponent 实现 OnInit, AfterViewInit {部门:部门[];selectedDepartment:部门;表单 = 新表单组({id: new FormControl(''),名字:new FormControl(''),姓氏:new FormControl(''),标题: new FormControl(''),率:新的FormControl(''),部门:new FormControl(''),});构造函数(私人部门服务:部门服务,私人服务:EmployeeService,public dialogRef: MatDialogRef,@Optional() @Inject(MAT_DIALOG_DATA) 公共数据:DialogData){if (data.action === '编辑') {this.form.patchValue(data.employee);}}ngOnInit() {this.departmentService.departments$.subscribe(r => {this.departments = r;});}//**** 据我所知,这实际上没有任何作用 ****ngAfterViewInit() {this.form.controls.department.setValue(this.data.employee.department);}createEmployee(f: FormGroup) {如果(this.data.action === '编辑'){this.service.updateEmployee(f.value).then(response => {this.closeDialog();});//创建一个新的} 别的 {this.service.createEmployee(f.value).then(response => {this.closeDialog();});}}onCancelClick() {this.onNoClick();}onNoClick() {this.dialogRef.close({事件:'取消'});}关闭对话框(){this.dialogRef.close({事件:this.data.action,数据:this.data.employee});}}

我使用以下命令在对话框底部显示数据":

{{ form.value |json }}</div>

它看起来像(它告诉我 Employee 对象可以很好地将其转移到对话框中):

<代码>{"id": "9UAPoKCFofH7aWBUwdiO","firstname": "约翰","lastname": "母鹿","title": "经理","率": "120",部门": {代码":1000","id": "2PtDUwPBXT7pUPWTOibD","title": "项目管理"}}

为了填充部门 mat-select,我使用了一项 CRUDs Firebase 服务:

 ngOnInit() {this.departmentService.departments$.subscribe(r => {this.departments = r;});}

模板中的相关 HTML:

<mat-label>部门</mat-label><mat-select formControlName="部门"><mat-option *ngFor="let dept of Department" [value]="dept">{{ 部门?.title }}</mat-option></mat-select></mat-form-field>

employee.ts

import { Department } from './department';导出接口员工{id:字符串;名字:字符串;姓氏:字符串;标题:字符串;部门:部门;率:数量;}

department.ts

导出接口部{id:字符串;标题:字符串;代码:字符串;}

解决方案

原因是你的员工记录中的部门对象与查询结果中的部门对象不匹配.是的,值匹配,但对象引用不匹配(它是一个单独的对象).

您可以使用 [compareWith] 属性传入一个比较对象 ID 的函数.mat-select 支持与标准 Angular select 相同的 [compareWith] 功能.https://angular.io/api/forms/SelectControlValueAccessor#customizing-option-选择

所以你会在你的模板中有这个:

然后在您的组件中:

compareFn(d1: Department, d2: Department): boolean {返回 d1 &&d2 ?d1.id === d2.id : d1 === d2;}

I'm losing it here. There are so many questions on this subject, and no matter what I try I can't get it to work.

I'm simply wanting to set the default value of a mat-select.

I have a list of Employees. Clicking on a list item opens a dialog (Employee Details) so I can edit (or add) the Employee's data. I just want the Department mat-select to display the Employee's current department when the mode is edit.

employee-details.component.html

<div fxLayout="column">
   <div class="flex-item" fxFlex mat-dialog-actions fxLayoutAlign="end">
      <button mat-mini-fab color="" aria-label="Cancel" (click)="onCancelClick()">
         <mat-icon>clear</mat-icon>
      </button>
   </div>
   <h4 *ngIf="data.action == 'add'">Add New Employee</h4>
   <h4 *ngIf="data.action == 'edit'">Edit Employee</h4>
   <form [formGroup]="form" class="employee-form">
      <div class="form-group">
         <mat-form-field class="employee-full-width">
            <input
               formControlName="firstname"
               matInput
               required
               placeholder="Employee Firstname"
               >
            <mat-error
               *ngIf="
               form.get('firstname').touched && form.get('firstname').invalid
               "
               >Employee Firstname is Required!</mat-error
               >
         </mat-form-field>
         <mat-form-field class="employee-full-width">
            <input
               formControlName="lastname"
               matInput
               required
               placeholder="Employee Lastname"
               >
            <mat-error
               *ngIf="
               form.get('lastname').touched && form.get('lastname').invalid
               "
               >Employee Lastname is Required!</mat-error
               >
         </mat-form-field>
         <mat-form-field class="employee-full-width">
            <input
               formControlName="title"
               matInput
               required
               placeholder="Employee Title"
               >
            <mat-error
               *ngIf="
               form.get('title').touched && form.get('title').invalid
               "
               >Employee Title is Required!</mat-error
               >
         </mat-form-field>
         <mat-form-field class="employee-full-width">
            <input
               formControlName="rate"
               matInput
               required
               placeholder="Employee Rate"
               >
            <mat-error
               *ngIf="
               form.get('rate').touched && form.get('rate').invalid
               "
               >Employee Rate is Required!</mat-error
               >
         </mat-form-field>
         <mat-form-field class="employee-full-width">
            <mat-label>Department</mat-label>
            <mat-select formControlName="department">
               <mat-option *ngFor="let dept of departments" [value]="dept">
               {{ dept?.title }}
               </mat-option>
            </mat-select>
         </mat-form-field>
      </div>
   </form>
   <div class="flex-item" fxFlex mat-dialog-actions fxLayoutAlign="end">
      <button
         mat-raised-button
         color="secondary"
         class="project-add-button"
         (click)="onNoClick()"
         >
      Cancel
      </button>
      <button
      mat-raised-button
      [disabled]="!form.valid"
      color="primary"
      class="project-add-button"
      (click)="createEmployee(form)"
      >
      Save & Close
      </button>
      <button
      mat-raised-button
      [disabled]="!form.valid"
      color="primary"
      class="project-add-button"
      (click)="createEmployee(form)"
      >
      Save & New
      </button>
   </div>
</div>
<div>
   <div>
      <br />
      <br />
      <mat-accordion>
         <mat-expansion-panel>
            <mat-expansion-panel-header>
               <mat-panel-title>
                  Form value
               </mat-panel-title>
            </mat-expansion-panel-header>
            <code>
               <div fxLayout="column" fxLayoutGap="32px">
                  <div>{{ form.value | json }}</div>
                  <div>Form Validity: {{ form.valid | json}}</div>
               </div>
            </code>
         </mat-expansion-panel>
      </mat-accordion>
   </div>
</div>

employee-details.component.ts

import { Component, OnInit, Optional, Inject, AfterViewInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { EmployeeService } from 'src/app/core/services/entity/employee.service';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { DialogData } from 'src/app/employees/employee-list/employee-list.component';
import { DepartmentService } from 'src/app/core/services/entity/department.service';
import { Department } from 'src/app/shared/models/department';

@Component({
  selector: 'app-employee-details',
  templateUrl: './employee-details.component.html',
  styleUrls: ['./employee-details.component.css']
})
export class EmployeeDetailsComponent implements OnInit, AfterViewInit {
  departments: Department[];
  selectedDepartment: Department;

  form = new FormGroup({
    id: new FormControl(''),
    firstname: new FormControl(''),
    lastname: new FormControl(''),
    title: new FormControl(''),
    rate: new FormControl(''),
    department: new FormControl(''),
  });

  constructor(
    private departmentService: DepartmentService,
    private service: EmployeeService,
    public dialogRef: MatDialogRef<EmployeeDetailsComponent>,
    @Optional() @Inject(MAT_DIALOG_DATA) public data: DialogData
  ) {
    if (data.action === 'edit') {
      this.form.patchValue(data.employee);
    }
  }

  ngOnInit() {
    this.departmentService.departments$.subscribe(r => {
      this.departments = r;
    });
  }
  // **** THIS DOESN'T ACTUALLY DO ANYTHING, AS FAR AS I CAN TELL ****
  ngAfterViewInit() {
    this.form.controls.department.setValue(this.data.employee.department);
  }

  createEmployee(f: FormGroup) {
    if (this.data.action === 'edit') {
      this.service.updateEmployee(f.value).then(response => {
        this.closeDialog();
      });
      // creating a new one
    } else {
      this.service.createEmployee(f.value).then(response => {
        this.closeDialog();
      });
    }
  }

  onCancelClick() {
    this.onNoClick();
  }

  onNoClick() {
    this.dialogRef.close({
      event: 'cancel'
    });
  }

  closeDialog() {
    this.dialogRef.close({
      event: this.data.action,
      data: this.data.employee
    });
  }
}

I'm displaying the 'data' at the bottom of the dialog using:

<div>{{ form.value | json }}</div>

and it looks like (which tells me the Employee object is making it over to the dialog just fine):

{
    "id": "9UAPoKCFofH7aWBUwdiO",
    "firstname": "John",
    "lastname": "Doe",
    "title": "Manager",
    "rate": "120",
    "department": {
        "code": "1000",
        "id": "2PtDUwPBXT7pUPWTOibD",
        "title": "Project Management"
    }
}

To populate the departments mat-select, I'm using a service which CRUDs Firebase:

  ngOnInit() {
    this.departmentService.departments$.subscribe(r => {
      this.departments = r;
    });
  }

The relevant HTML from the template:

<mat-form-field class="employee-full-width">
  <mat-label>Department</mat-label>
    <mat-select formControlName="department">
      <mat-option *ngFor="let dept of departments" [value]="dept">
       {{ dept?.title }}
      </mat-option>
    </mat-select>
</mat-form-field>

employee.ts

import { Department } from './department';

export interface Employee {
    id: string;
    firstname: string;
    lastname: string;
    title: string;
    department: Department;
    rate: number;
}

department.ts

export interface Department {
    id: string;
    title: string;
    code: string;
}

解决方案

The reason is because the department object in your employee record does not match the department object in your query result. Yes, the values match, but the object reference does not match (its a separate object).

You can use the [compareWith] attribute to pass in a function that compares the ids of the objects. mat-select supports the same [compareWith] functionality as the standard Angular select. https://angular.io/api/forms/SelectControlValueAccessor#customizing-option-selection

So you would have this in your template:

<mat-select formControlName="department" [compareWith]="compareFn">

And then in your component:

compareFn(d1: Department, d2: Department): boolean {
    return d1 && d2 ? d1.id === d2.id : d1 === d2;
}

这篇关于Angular Material Select - 默认值 - Reactive Forms的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆