typescript Angular在打开进行编辑时无法在React式表单中填充mat-select控件

vptzau2j  于 2023-06-07  发布在  TypeScript
关注(0)|答案(1)|浏览(139)

我是新的Angular ,我认为我已经浪费了很多时间在一个非常简单的步骤。
我有一个非常简单的表单,用于在数据库中创建Question实体。创建记录时,表单似乎工作正常。但是,当其打开以编辑现有记录时,“mat-selct”控制字段未被填充。这些下拉菜单也是从API加载的。
下面是代码。

component.ts

import { Component, Inject, inject, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, FormGroupDirective, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Observable } from 'rxjs';
import { Question } from 'src/app/Models/Question';
import { QuestionCategory } from 'src/app/Models/QuestionCategory';
import { QuestionType } from 'src/app/Models/QuestionType';
import { StResponse } from 'src/app/Models/StResponse';
import { QuestionCategoryService } from 'src/app/Services/question-category.service';
import { QuestionTypeService } from 'src/app/Services/question-type.service';
import { QuestionService } from 'src/app/Services/question.service';

@Component({
  selector: 'app-question-form',
  templateUrl: './question-form.component.html',
  styleUrls: ['./question-form.component.scss']
})
export class QuestionFormComponent implements OnInit {

  // model: Question;
  @ViewChild(FormGroupDirective)
  formDirective!: FormGroupDirective;
  questionForm!: FormGroup

  questionTypes: QuestionType[] = []
  questionCategories: QuestionCategory [] = [];

  constructor(private _fb: FormBuilder, 
              private _service: QuestionService,
              private _quesCategoryServ: QuestionCategoryService,
              private _quesTypeServ: QuestionTypeService,
              @Inject(MAT_DIALOG_DATA) private data: Question
              ) {
    
  }

  ngOnInit(): void {
    console.log('QF Oninit', this.data);
    this._quesCategoryServ.getAll().subscribe((sr:StResponse)=>{
      console.log('QesComp:', sr.data)
      this.questionCategories = sr.data.QuestionCategory;
    });
    this._quesTypeServ.getAll().subscribe((sr:StResponse)=>{
      console.log('QesComp:', sr.data)
      this.questionTypes = sr.data.QuestionType;
    });

    this.questionForm = this._fb.group({
      shortText: ['',Validators.required],
      text: ['',Validators.required],
      textInfo: [''],
      questionType: [null,Validators.required],
      questionCategory:[null,Validators.required],
    });

    if(this.data){
      console.log('oninit-forEdit')
      this.questionForm.patchValue({
        shortText: this.data.shortText,
        text: this.data.text,
        textInfo: this.data.textInfo,
        questionType: this.data.questionType,
        questionCategory: this.data.questionCategory,
      });

    }
  }

  onFormSubmit():void {
    if(this.questionForm.valid){
      console.log('submited form values',this.questionForm.value);
      this._service.add(this.questionForm.value).subscribe({
        next: (val: StResponse) => {
          alert('Question Added')
          // this.questionForm.reset();
          this.formDirective.resetForm();
          console.log('form resetted!')
        },
        error: (err: any) =>{
          console.error(err);
        }
      })
    }
  }
  
  // FormControl fields references for validation
  get shortText() { return this.questionForm.get('shortText'); }
  get text() { return this.questionForm.get('text'); }
  get textInfo() { return this.questionForm.get('textInfo'); }
  get questionType() { return this.questionForm.get('questionType'); }
  get questionCategory() { return this.questionForm.get('questionCategory'); }

}

component.html

<h1 mat-dialog-title>Question</h1>
<form [formGroup]="questionForm" (ngSubmit)="onFormSubmit()">
    <div mat-dialog-content class="content">
        <div class="row">
            <mat-form-field appearance="outline">
                <mat-label>Short Text</mat-label>
                <input matInput type="text" placeholder="Ex. Wheels." formControlName="shortText">
                <mat-error *ngIf="shortText?.invalid">Enter short text.</mat-error>
            </mat-form-field>
        </div>
        <div class="row">
            <mat-form-field appearance="outline">
                <mat-label>Question</mat-label>
                <input matInput type="text" placeholder="Ex. Undamaged, All nuts tight." formControlName="text">
                <mat-error *ngIf="text?.invalid">Please enter question text.</mat-error>
            </mat-form-field>
        </div>
        <div class="row">
        <mat-form-field appearance="outline">
            <mat-label>Details</mat-label>
            <textarea matInput placeholder="Ex. Any details to further explain this question." formControlName="textInfo"></textarea>
        </mat-form-field>
        </div>

        <div class="row">
            <mat-form-field appearance="outline">
                <mat-label>Type</mat-label>
                <mat-select formControlName="questionType" >
                    <mat-option *ngFor="let typeOption of questionTypes" [value]="typeOption"> 
                    {{typeOption.code}} 
                    </mat-option>
                </mat-select>
                <mat-error *ngIf="questionType?.invalid">You must make a selection</mat-error>
            </mat-form-field>
        </div>
        <div class="row">
            <mat-form-field appearance="outline">
                <mat-label>Category</mat-label>
                <mat-select formControlName="questionCategory" >
                    <mat-option *ngFor="let categoryOption of questionCategories" [value]="categoryOption">
                    {{categoryOption.code}}
                    </mat-option>
                </mat-select>
                <mat-error *ngIf="questionCategory?.invalid">You must make a selection</mat-error>
            </mat-form-field>
        </div>
    </div>
    <div mat-dialog-actions class="action">
    <button mat-raised-button mat-dialog-close>Close</button>
    <button mat-raised-button color="primary" type="submit">save</button>
    </div>
</form>
export class Question{
    id: number;
    shortText: string;
    text: string;
    textInfo: string;
    questionType: QuestionType;
    questionCategory: QuestionCategory;

    constructor(){
        this.id = 0;
        this.shortText = '';
        this.text = '';
        this.textInfo = '';
        this.questionType = new QuestionType();
        this.questionCategory = new QuestionCategory();
    }
}

export class QuestionType{
    id: number;
    code: string;

    constructor(){
        this.id = 0;
        this.code = '';
    }
}

export class QuestionCategory{
    id: number;
    code: string;
    name: string;

    constructor(){
        this.id = 0;
        this.code = '';
        this.name = '';
    }
}

一些其他发现正在填充shortText、text、TextInfo的其他输入。只有“垫选择”未加载。我一定是错过了一些愚蠢的事情,因为即使是选择的值也没有填充,它们就像我在编辑时将它们保留为空白,然后再次按保存。这些值被提交并保存在数据库中。

我也试过form.setValue()方法,但仍然没有运气。

// part of ngOnInit()

    if(this.data){
      console.log('oninit-forEdit')
      this.questionForm.patchValue({
        shortText: this.data.shortText,
        text: this.data.text,
        textInfo: this.data.textInfo,
        // questionType: this.data.questionType,
        // questionCategory: this.data.questionCategory,
      });

      const selectedCategory = this.questionCategories.find(category => category.id === this.data.questionCategory.id);
      const selectedType = this.questionTypes.find(type => type.id === this.data.questionType.id);

      this.questionForm.get('questionCategory')?.setValue(selectedCategory);
      this.questionForm.get('questionType')?.setValue(selectedType);
    }
  }

任何帮助或指导都会有帮助。谢谢

cvxl0en2

cvxl0en21#

当决定将哪个选项标记为选中时,Angular通过标识(===)比较值。
这在编辑表单时不起作用,因为当前表单控件值不等于列表中的任何值,即。它们不是相同的对象(即使它们具有相同的结构)。
questionTypes是通过调用this._quesTypeServ.getAll获取的,当前表单控件值为data.questionType
要让Angular以其他方式比较值,您可以使用compareWith输入SelectControlValueAccessor
我们可以通过id比较值,因为该属性对于每个对象都是唯一的:

compareFn(a: QuestionType, b: QuestionType): boolean {
    return a && b ? (a.id === b.id) : (a === b);
}

在模板中:

<mat-select formControlName="questionType" [compareWith]="compareFn">
    <mat-option *ngFor="let typeOption of questionTypes" [value]="typeOption"> 
        {{typeOption.code}} 
    </mat-option>
</mat-select>

关于compareWith的文档:https://angular.io/api/forms/SelectControlValueAccessor#customizing-option-selection

相关问题