【问题标题】:angular reactive form throws "Cannot find control with name" for irrelevant model field角度反应形式为不相关的模型字段抛出“找不到具有名称的控件”
【发布时间】:2020-05-07 07:42:00
【问题描述】:

我正在尝试使用 Angular Reactive 表单构建一个编辑组件。但是,我收到错误“错误:找不到名称为已创建的表单控件。”,其中“已创建”是我模型上的属性。

但是,created 不是可编辑字段,不应绑定到表单。我没有在我的表单生成器中指定它,我的 edit.html 页面上也没有控件。它只出现在我的模型上。我如何告诉表单验证器忽略这个和其他不相关的模型属性?

这是我的模型:

        export class User {
      id: number;
      userName: string;
      password: string;
      passwordHash: string;
      lastName: string;
      firstName: string;
      email: string;
      created: string;
      lastLogin: string;
      description: string;
      isSaved: boolean;
      passsword:string;
      passwordConfirm:string;
    }

这是我的组件:

    import { Component, OnInit, Inject } from '@angular/core';
import { Router } from "@angular/router";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { first } from "rxjs/operators";
import { User } from "../../model/user.model";
import { UserService } from "../../service/user.service";


@Component({
  selector: 'app-edit-user',
  templateUrl: './edit-user.component.html',
  styleUrls: ['./edit-user.component.css']
})
export class EditUserComponent implements OnInit {

  user: User;
  editForm: FormGroup;

  constructor(private formBuilder: FormBuilder, private router: Router, private userService: UserService) { }

  ngOnInit() {
    let userId = window.localStorage.getItem("editUserId");
    if (!userId) {
      alert("Invalid action.")
      this.router.navigate(['list-user']);
      return;
    }
    this.editForm = this.formBuilder.group({
      id: [''],
      userName: ['', Validators.required],
      password: ['', Validators.required],
      passwordConfirm: ['', Validators.required],
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      email: ['', Validators.email],
      description: [''],
    });
    this.userService.getUserById(+userId)
      .subscribe(data => {
        this.editForm.setValue(data);
      });
  }

  onSubmit() {

    if(!this.editForm.value.passwordConfirm){
      console.log("password confirmed is undefined. Setting");
      this.editForm.value.passwordConfirm = this.editForm.value.password;
    }

    this.userService.updateUser(this.editForm.value)
      .pipe(first())
      .subscribe(
        data => {
          alert('User updated successfully.');
          this.router.navigate(['list-user']);
        },
        error => {
          alert("En error occured and changes should not be saved. Details: " + error);
        });
  }
}

这是我的html:

        <div class="col-md-6 user-container">
          <h2 class="text-center">Edit User</h2>
          <form [formGroup]="editForm" (ngSubmit)="onSubmit()">

            <div class="hidden" style="display:none;">
              <input type="text" formControlName="id" placeholder="id" name="id" class="form-control" id="id">
            </div>

            <!-- todo: replace display none with bootstrap class -->

            <div class="form-group" style="display:none;">
              <input type="text" formControlName="userName" placeholder="userName" name="userName" class="form-control"
                id="userName" readonly="true">
            </div>

            <div class="form-group">
              <label for="firstName">First Name:</label>
              <input formControlName="firstName" placeholder="First Name" name="firstName" class="form-control" id="firstName">
            </div>

            <div class="form-group">
              <label for="lastName">Last Name:</label>
              <input formControlName="lastName" placeholder="Last name" name="lastName" class="form-control" id="lastName">
            </div>

            <div class="form-group">
              <label for="email">Email:</label>
              <input formControlName="email" placeholder="email" name="email" class="form-control" id="email">
            </div>

            <div class="form-group">
              <label for="description">Description:</label>
              <input formControlName="description" placeholder="Description" name="description" class="form-control"
                id="description">
            </div>

            <hr>

            <h5>Change password</h5>

            <div class="form-group">
              <label for="password">New password:</label>
              <input type="password" formControlName="password" placeholder="password" name="password" class="form-control"
                id="password">
            </div>

            <div class="form-group">
              <label for="passwordConfirm">Confirm password:</label>
              <input type="password" formControlName="passwordConfirm" placeholder="passwordConfirm" name="passwordConfirm"
                class="form-control" id="passwordConfirm">
            </div>

            <button class="btn btn-success">Update</button>
          </form>
        </div>

这是错误详情:

错误:找不到名称为已创建的表单控件。 core.js:5847 消息:“找不到名称为已创建的表单控件。” 堆栈:“错误:找不到名称为已创建的表单控件。\n 在 FormGroup._throwIfControlMissing (https://localhost:5001/vendor.js:70056:19)\n 在 https://localhost:5001/vendor.js:69913:19\n 在 Array.forEach ()\n 在 FormGroup.setValue (https://localhost:5001/vendor.js:69912:28) \n 在 SafeSubscriber._next (https://localhost:5001/main.js:1937:28)\n 在 SafeSubscriber.__tryOrUnsub (https://localhost:5001/vendor.js:95425:16)\n 在 SafeSubscriber.next (https://localhost:5001/vendor.js:95363:22)\n 在 Subscriber._next (https://localhost:5001/vendor.js:95309:26)\n 在 Subscriber.next (https://localhost:5001/vendor.js:95286:18)\n 在 MapSubscriber._next (https://localhost:5001/vendor.js:100330:26)"

【问题讨论】:

  • 可能 created 通过这行代码添加到 editForm - this.editForm.setValue(data);。你能console.log检查一下吗?
  • 是的,“数据”包含来自我的 API 的整个用户模型对象:对象 {firstName:“FirstName”,lastName:“LastName”,密码:null,created:“2020-01-21T10: 48:47.4345182+01:00", lastLogin: "2020-01-20T15:31:30.277", ...} 等等...
  • 所以,将editFormformModel 分开。从formModel 填充editFormeditForm 将仅包含表单上所需的字段。 formModel 将包含所有字段并匹配 API 返回的架构。

标签: javascript angular typescript angular-reactive-forms form-control


【解决方案1】:

您似乎想在表单中设置一个User 对象,该对象没有名为created 的控件。

您要么从传递给setValue 的对象中删除该字段,要么使用patchValue 代替patchValue,这似乎忽略了未知字段,并且仅触及那些在对象传入并单独保留其他控件,而不是setValue,后者重置那些未在传入对象中指定的控件。

【讨论】:

  • 谢谢! patchValue() 成功了。我应该补充一点,我认为 setValue() 的行为很奇怪,要求模型中的所有字段都必须在表单中。您多久拥有一个与您的表单完全对应的模型?您必须为每种表单提供一个独特的模型。
  • 我有点同意这一点,但也同意表单 API 强制您显式处理从模型到表单的转换。有时,对于更复杂的表单,我什至为表单值创建一个接口,编写单独的转换器(当您从表单中提取数据以将其传递到后端时,您可能也需要一个转换器)并测试这些.
【解决方案2】:

Angular 反应式表单仅接受表单构建器中存在的那些值,如果您在对象中有一些额外的属性,您正在使用设置值,它会为该属性提供错误。在这里,你有额外的created,如果你以某种方式解决了这个错误,它会再次给lastLogin提供错误,因为它不是表单生成器的一部分。

this.userService.getUserById(+userId)
  .subscribe(data => {
   const propertyToSelect = ['id','userName', 'password','passwordConfirm', 'firstName', 'lastName','email', 'description']
   const objectToSetValue = propertyToSelect.map((property) => {property: data[property]})
   this.editForm.setValue(objectToSetValue);
  });

【讨论】:

    猜你喜欢
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2019-02-25
    • 2017-05-18
    • 1970-01-01
    • 2021-11-25
    相关资源
    最近更新 更多