a_l_e_x
a_l_e_x

Reputation: 400

Warning: ngModel on the same form field as formControlName

warning

While executing the code I don't get any errors; I have a problem when I click the Update button. In other words, I receive this notice:

It looks like you're using ngModel on the same form field as formControlName. Support for using the ngModel input property and ngModelChange event with reactive form directives has been deprecated in Angular v6 and will be removed in 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;  
  }

Upvotes: 1

Views: 7044

Answers (1)

Rich Tillis
Rich Tillis

Reputation: 1571

The Angular docs have a forms overview guide which describes different considerations when deciding which form design to use:

Reactive forms provide direct, explicit access to the underlying forms object model. Compared to template-driven forms, they are more robust: they're more scalable, reusable, and testable. If forms are a key part of your application, or you're already using reactive patterns for building your application, use reactive forms.

Template-driven forms rely on directives in the template to create and manipulate the underlying object model. They are useful for adding a simple form to an app, such as an email list signup form. They're easy to add to an app, but they don't scale as well as reactive forms. If you have very basic form requirements and logic that can be managed solely in the template, template-driven forms could be a good fit.

I put together a small angular app containing both form types for reference. It does not include all the bells and whistles each form type offers but hopefully it will get you moving. Here is the github repo and the Stackblitz for reference.

Here is an example of the template-driven approach:

<!-- 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;
  }
}

And here is an example of the reactive approach:

<!-- 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();
  }
}

I would recommend reading the angular docs and guides on forms. They are good.

Upvotes: 2

Related Questions