【问题标题】:Warning: ngModel on the same form field as formControlName警告:ngModel 在与 formControlName 相同的表单字段上
【发布时间】:2021-07-07 02:00:33
【问题描述】:

warning

在执行代码时,我没有收到任何错误;单击更新按钮时出现问题。 换句话说,我收到了这样的通知:

您似乎在与 formControlName 相同的表单字段上使用 ngModel。 Angular v6 中已弃用对使用 ngModel 输入属性和 ngModelChange 事件的响应式表单指令的支持,并将在 Angular v7 中删除。

product-list.component.html

<div class="panel panel-default">  
      <div class="panel-heading">  
          <h1 style="text-align: center">Products</h1><br>  
          <div class="row" [hidden]="!deleteMessage">  
                 
                    <div class="col-sm-4"></div>  
                    <div class="col-sm-4">  
                            <div class="alert alert-info alert-dismissible">  
                                    <button type="button" class="close" data-dismiss="alert">×</button>  
                                    <strong>Product Data Deleted</strong>  
                            </div>  
                    </div>  
                    <div class="col-sm-4"></div>  
            </div>             
        </div>  
      
        
      <div class="panel-body">  
          <table  class="table table-hover table-sm" datatable [dtOptions]="dtOptions"  
          [dtTrigger]="dtTrigger"  >  
              <thead class="thead-light">  
                  <tr>  
                      <th>Product Name</th>  
                      <th>Product Variety</th>  
                      <th>Product Origin</th>  
                      <th>Action</th>  
                        
                  </tr>  
              </thead>  
              <tbody>  
                   <tr *ngFor="let product of products ">  
                      <td>{{product.product_name}}</td>  
                      <td>{{product.product_variety}}</td>  
                      <td>{{product.product_origin}}</td>  
                      <td><button (click)="deleteProduct(product.product_id)" class='btn btn-primary'><i class="fa fa-futboll-0">Delete</i></button>   
                        <button (click)="updateProduct(product.product_id)" class='btn btn-info'  
                        data-toggle="modal" data-target="#myModal">Update</button>  
                      </td>  
                    </tr>   
              </tbody><br>  
          </table>  
      </div>  
    </div>   
      
    <div class="modal" id="myModal">  
            <div class="modal-dialog">  
              <div class="modal-content">  
                    <form [formGroup]="productupdateform" #updprod (ngSubmit)="updateprod(updprod)">  
                <!-- Modal Header -->  
                <div class="modal-header">  
                  <h4 class="modal-title" style="text-align: center">Update Product</h4>  
                    
                </div>  
                  
                <!-- Modal body -->  
                <div class="modal-body" *ngFor="let product of productlist " >  
                    <div [hidden]="isupdated">  
      
                        <input type="hidden" class="form-control"  formControlName="product_id" [(ngModel)]="product.product_id">  
                                <div class="form-group">  
                                    <label for="name">Product Name</label>  
                                    <input type="text" class="form-control"  formControlName="product_name" [(ngModel)]="product.product_name"  >  
                                </div>  
                          
                                <div class="form-group">  
                                    <label for="name">Product Variety</label>  
                                    <input type="text" class="form-control" formControlName="product_Variety" [(ngModel)]="product.product_Variety">  
                                </div>  
                          
                                <div class="form-group">  
                                    <label for="name">Product Origin</label>  
                                    <input type="text" class="form-control" formControlName="product_origin" [(ngModel)]="product.product_origin"
                                </div>                     
                      </div>    
                      <div [hidden]="!isupdated">  
                          <h4>Product Detail Updated!</h4>  
                      </div>          
                          
                </div>  
                  
                <!-- Modal footer -->  
                <div class="modal-footer" >  
                  <button type="submit" class="btn btn-success" [hidden]="isupdated">Update</button>  
                  <button type="button" class="btn btn-danger" data-dismiss="modal" (click)="changeisUpdate()">Close</button>  
                </div>  
                  
            </form>  
              </div>  
            </div>  
          </div>  

product-list.component.ts

import { Component, OnInit } from '@angular/core';  
import { ProductService } from '../product.service';  
import { Product } from '../product';  
import { Observable,Subject } from "rxjs";  
  
import {FormControl,FormGroup,Validators} from '@angular/forms';  
  
@Component({  
  selector: 'app-product-list',  
  templateUrl: './product-list.component.html',  
  styleUrls: ['./product-list.component.css']  
})  
export class ProductListComponent implements OnInit {  
  
 constructor(private productservice:ProductService) { }  
  
  productsArray: any[] = [];  
  dtOptions: DataTables.Settings = {};  
  dtTrigger: Subject<any>= new Subject();  
  
  products: Observable<Product[]>;  
  product : Product=new Product();  
  deleteMessage=false;  
  productlist:any;  
  isupdated = false;      
   
  
  ngOnInit() {  
    this.isupdated=false;  
    this.dtOptions = {  
      pageLength: 6,  
      stateSave:true,  
      lengthMenu:[[6, 16, 20, -1], [6, 16, 20, "All"]],  
      processing: true  
    };     
    this.productservice.getProductList().subscribe(data =>{  
    this.products =data;  
    this.dtTrigger.next();  
    })  
  }  
    
  deleteProduct(id: number) {  
    this.productservice.deleteProduct(id)  
      .subscribe(  
        data => {  
          console.log(data);  
          this.deleteMessage=true;  
          this.productservice.getProductList().subscribe(data =>{  
            this.products =data  
            })  
        },  
        error => console.log(error));  
  }  
  
  updateProduct(id: number){  
    this.productservice.getProduct(id)  
      .subscribe(  
        data => {  
          this.productlist=data             
        },  
        error => console.log(error));  
  }  
  
  productupdateform=new FormGroup({  
    product_id:new FormControl(),  
    product_name:new FormControl(),  
    product_variety:new FormControl(),  
    product_origin:new FormControl()  
  });  
  
  updateProd(updprod){  
    this.product=new Product();   
   this.product.product_id=this.ProductId.value;  
   this.product.product_name=this.ProductName.value;  
   this.product.product_variety=this.ProductVariety.value;  
   this.product.product_origin=this.ProductOrigin.value;  
   console.log(this.ProductOrigin.value);  
     
  
   this.productservice.updateProduct(this.product.product_id,this.product).subscribe(  
    data => {       
      this.isupdated=true;  
      this.productservice.getProductList().subscribe(data =>{  
        this.products =data  
        })  
    },  
    error => console.log(error));  
  }  
  
  get ProductName(){  
    return this.productupdateform.get('product_name');  
  }  
  
  get ProductVariety(){  
    return this.productupdateform.get('product_variety');  
  }  
  
  get ProductOrigin(){  
    return this.productupdateform.get('product_origin');  
  }  
  
  get ProductId(){  
    return this.productupdateform.get('product_id');  
  }  
  
  changeisUpdate(){  
    this.isupdated=false;  
  }

【问题讨论】:

  • 您希望您的表单设计为模板驱动表单还是响应式表单?看起来您正在为两种表单设计类型使用指令。
  • 使用响应式表单不是更好吗?你有什么建议?如何修改代码以使其正常工作?
  • 响应式表单和模板驱动表单都很好。选择一个适合您的解决方案。显然,同时使用两者是行不通的。
  • 如何更改代码?我是初学者
  • 我正在尝试遵循您的代码,而您有 productsproductList,您如何使用它们?

标签: javascript angular


【解决方案1】:

Angular 文档有一个forms overview guide,它描述了在决定使用哪种表单设计时的不同注意事项:

反应式表单提供对底层表单对象模型的直接、显式访问。与模板驱动的表单相比,它们更健壮:它们更具可扩展性、可重用性和可测试性。如果表单是您的应用程序的关键部分,或者您已经在使用响应式模式来构建您的应用程序,请使用响应式表单。

模板驱动的表单依靠模板中的指令来创建和操作底层对象模型。它们对于向应用程序添加简单的表单很有用,例如电子邮件列表注册表单。它们很容易添加到应用程序中,但它们的扩展性不如响应式表单。如果您有非常基本的表单要求和可以单独在模板中管理的逻辑,那么模板驱动的表单可能是一个不错的选择。

我整理了一个包含两种表单类型的小型 Angular 应用程序以供参考。它不包括每种表单类型提供的所有花里胡哨,但希望它能让你感动。这是github repoStackblitz 供参考。

以下是模板驱动方法的示例:

<!-- template-driven html -->
<div>
  <table>
    <thead><tr><th>Product Name</th><th>Product Variety</th><th>Product Origin</th><th>Action</th></tr></thead>
    <tbody>
      <tr *ngFor="let product of productlist | async">
        <td>{{product.product_name}}</td>
        <td>{{product.product_variety}}</td>
        <td>{{product.product_origin}}</td>
        <td>
          <button (click)="setProductForm(product.product_id)">Update</button>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<div *ngIf="isEditing">
  <form novalidate #productForm (ngSubmit)="updateProduct()">

    <div><input name="productId" type="hidden" [(ngModel)]="product_id"></div>

    <div>
      <label for="productName">Product Name </label>
      <input id="productName" name="productName" type="text" [(ngModel)]="product_name" required>
    </div>

    <div>
      <label for="productVariety">Product Variety </label>
      <input id="productVariety" name="productVariety" type="text" [(ngModel)]="product_variety">
    </div>

    <div>
      <label for="productOrigin" >Product Origin</label>
      <input id="productOrigin" name="productOrigin" type="text" [(ngModel)]="product_origin">
    </div>

    <button type="submit">Update</button>

  </form>
</div>
//template-driven.component.ts
export class TemplateDrivenComponent {
  productlist: Observable<Product[]> = this.productservice.getProductList();
  isEditing = false;
  product_id: number;
  product_name: string;
  product_variety: string;
  product_origin: string;

  constructor(private productservice: ProductService) { }

  setProductForm(id: number) {
    const product: Product = this.productservice.getProduct(id);
    this.product_id = product.product_id;
    this.product_name = product.product_name;
    this.product_variety = product.product_variety;
    this.product_origin = product.product_origin;
    this.isEditing = true;
  }

  updateProduct() {
    let product: Product = new Product();
    product.product_id = this.product_id;
    product.product_name = this.product_name;
    product.product_origin = this.product_origin;
    product.product_variety = this.product_variety;
    this.productservice.updateProduct(product);
    this.resetForm();
  }

  resetForm() {
    this.isEditing = false;
    this.product_id = null;
    this.product_name = null;
    this.product_variety = null;
    this.product_origin = null;
  }
}

这里是反应式方法的一个例子:

<!-- reactive html-->
<div>
  <table>
    <thead>
      <tr>
        <th>Product Name</th>
        <th>Product Variety</th>
        <th>Product Origin</th>
        <th>Action</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let product of productlist | async">
        <td>{{product.product_name}}</td>
        <td>{{product.product_variety}}</td>
        <td>{{product.product_origin}}</td>
        <td>
          <button (click)="setProductForm(product.product_id)">Update</button>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<div *ngIf="isEditing">
  <form novalidate [formGroup]="productupdateform" (ngSubmit)="updateProduct()">

    <div><input type="hidden" formControlName="theProductId"></div>

    <div>
      <label>Product Name
        <input type="text" formControlName="theProductName">
      </label>
    </div>

    <div>
      <label>Product Variety
        <input type="text" formControlName="theProductVariety">
      </label>
    </div>

    <div>
      <label>Product Origin
        <input type="text" formControlName="theProductOrigin">
      </label>
    </div>

    <button type="submit" >Update</button>

  </form>
</div>
//reactive.component.ts
export class ReactiveComponent implements OnInit {

  productupdateform: FormGroup;
  productlist: Observable<Product[]> = this.productservice.getProductList()
  isEditing = false;

  constructor(private productservice: ProductService, private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.initializeForm();
  }

  initializeForm() {
    this.productupdateform = this.formBuilder.group({
      theProductId: [0],
      theProductName: ['', Validators.required],
      theProductVariety: [''],
      theProductOrigin: ['']
    })
  }

  setProductForm(id: number) {
    const product = this.productservice.getProduct(id);
    this.productupdateform.patchValue({
      theProductId: product.product_id,
      theProductName: product.product_name,
      theProductVariety: product.product_variety,
      theProductOrigin: product.product_origin
    });
    this.productupdateform.updateValueAndValidity();
    this.isEditing = true;
  }

  updateProduct() {
    let product: Product = {
      product_id: this.productupdateform.get('theProductId').value,
      product_name: this.productupdateform.get('theProductName').value,
      product_variety: this.productupdateform.get('theProductVariety').value,
      product_origin: this.productupdateform.get('theProductOrigin').value
    }
    this.productservice.updateProduct(product);
    this.resetForm();
  }

  isFormValid() {
    return true;
  }

  resetForm() {
    this.isEditing = false;
    this.initializeForm();
  }
}

我建议阅读有关表单的 angular 文档和指南。他们很好。

【讨论】:

  • 我想私下联系你。可以有你的邮箱吗?
  • @f_u_s_e_d 你可以通过richtillis.com找到联系我的方法
  • 我给你发了一封电子邮件。感谢之前的回答,清晰准确
猜你喜欢
  • 2019-07-08
  • 2018-09-29
  • 2019-06-11
  • 1970-01-01
  • 2021-12-25
  • 2018-12-16
  • 2011-04-05
  • 2021-01-01
  • 1970-01-01
相关资源
最近更新 更多