【问题标题】:Default Select option Angular 8 Reactive forms默认选择选项Angular 8 Reactive forms
【发布时间】:2019-11-03 20:22:15
【问题描述】:

我想从我的 API 中获取我的所有数据并将它们设置为我的响应式表单的默认值。我能够使用ngModel 绑定所有值。我只是不知道如何用我的select 做到这一点。在我的 HTML 中,我从我的家庭服务中获得了我的第一个选择选项。第二个选项,我正在使用我的类别服务来显示所有类别。我这样做是为了能够根据我当前选择的产品设置默认值。我遇到的主要问题是我想将 ngModel 绑定到第一个选项,这样默认情况下,如果我要提交我的表单,它将是提交的第一个选项。我见过人们使用补丁值来执行此操作,但我的问题是我不知道如何处理通过我的 html 获取的数据,因为它显示在 html 中而不是 ts 文件中。使用ngModel是我能想到的最佳解决方案。

html

  <!-- Table -->
  <form  [formGroup]="updateProduct" >
      <p>
          Form Status: {{updateProduct.value |json}}
        </p>
  <div class="table-responsive">
     
    <table  class="table table-bordered table-striped">
      <thead>
      <tr>
        <th>Id</th>
        <th>Product</th>
        <th>Category</th>
        <th>FullPrice <i id ="asc-desc1"class="fas fa-angle-down" (click)="SortPrice($event)"></i></th>
        <th>Saleprice <i id ="asc-desc2"class="fas fa-angle-down" (click)="SortSale($event)"></i> </th>
        <th>Availablity</th>
        <th>Supplier</th>
        <th>Discount<i id ="asc-desc3"class="fas fa-angle-down" (click)="SortDiscount($event)"></i></th>
        <th>Edit</th>
      </tr>
      </thead>
      <tbody>
          
        <tr  *ngFor="let home of home | paginate:{itemsPerPage:20,currentPage: p} ; index as i">
        <ng-container *ngIf="editMode !== i">
        <td>{{home.id}}</td>
        <td>{{home.productName}}</td>
        <td>{{home.category.categoryName}}</td>
        <td>{{home.fullPrice}}</td>
        <td>{{home.salePrice}}</td>
        <td>{{home.availability}}</td>
        <td>{{home.supplier.supplierName}}</td>
        <td>{{home.discount }}</td>
      </ng-container>
      <ng-container *ngIf="editMode === i">
          
          <td><input class="form-control" id="id"  formControlName="id" [(ngModel)]="home.id" disabled></td>
          <td><input class="form-control" id="productName"  formControlName="productName" [(ngModel)]="home.productName"></td>
          <td>
              <select class="form-control" formControlName="category" >
                <option selected="selcected"  class="opt1" >{{home.category.categoryName}}</option>
                <option *ngFor="let category of categories">{{category.categoryName}}</option>
              </select>
            </td>
          <td><input class="form-control" id="fullprice" formControlName="fullPrice" [(ngModel)]="home.fullPrice"></td>
          <td><input class="form-control" id="saleprice"   formControlName="salePrice" [(ngModel)]="home.salePrice"></td>
          <td><input type="checkbox" class="form-control" id="availability"  formControlName="availability" [(ngModel)]="home.availability"></td>
          <td>
            <select class="form-control" formControlName="supplier">
              <option selected="selcected" class="opt1">{{home.supplier.supplierName}}</option>
              <option *ngFor="let supplier of suppliers">{{supplier.supplierName}}</option>
            </select>
          </td>
          <td><input class="form-control" id="discount" formControlName="discount"[(ngModel)]="home.discount"></td>
     
        </ng-container>


      <!-- if assigned index to editMode matches -->
      
        <td class="text-right" id="tableDataBtns">
          <div class="btn-group" role="group">
            <button (click)="editMode === i ? editMode = null : editMode = i" data-toggle="modal" data-target="#updateProduct" type="button" class="btn btn-secondary">
              <ng-container *ngIf="editMode === i"><i class="far fa-save"></i></ng-container>
              <ng-container *ngIf="editMode !== i"><i class="far fa-edit"></i></ng-container>
            </button>
            <button type="button" data-toggle="modal" data-target="#deleteProduct" class="btn btn-danger"><i class="far fa-trash-alt"></i></button>
          </div>
        </td>
      </tr>
      </tbody>
    </table>

    <pagination-controls class="myPagination" (pageChange)="p= $event"></pagination-controls>
  </div>
  </form>
ts

import { Component, OnInit } from '@angular/core';
import { Product } from '../model/Product';
import { Category } from '../model/Availability';
import { Supplier } from '../model/Supplier';
import { Home } from '../model/Home';
import { HomeService } from '../service/Home.service';
import { SupplierService } from '../service/Supplier.service';
import { CategoryService } from '../service/Category.service';
import { FormGroup, FormControl } from '@angular/forms'
@Component({
  selector: 'app-update-product',
  templateUrl: './update-product.component.html',
  styleUrls: ['./update-product.component.scss']
})
export class UpdateProductComponent implements OnInit {
  availability:boolean;
  category:number;
  orderBy: String;
  Ascdesc: String;
  page = 0;
  home: Home[];
  categories: Category[];
  suppliers: Supplier[];
  selectedCategory: Category;
  edit: boolean = false;
  public currentProduct: number;

  toogleEditMode() {
    this.edit = this.edit ? false : true; 
  }
    
  selectCategory (category) {
       this.category = category.category;
   }
  
   available(boolean){
  
    this.availability = boolean;
    }
  
    update($event){
      this.homeService.getByParm(this.availability,this.category).subscribe(data => {
        this.home = data;
      }); 
  
    }
    updateProduct = new FormGroup({
      id: new FormControl(''),
      productName: new FormControl(''),
      category: new FormControl(''),
      fullPrice: new FormControl(''),
      salePrice: new FormControl(''),
      availability: new FormControl(''),
      supplier: new FormControl(''),
      discount: new FormControl(''),

    });

// model = {id: null, productName: '', category: {category: null, categoryName: null}, fullPrice: '', salePrice:'', availability: false, supplier: {supplier:null,supplierName:""},discount:null};
// json = JSON.stringify(this.model);
constructor(private homeService: HomeService,private supplierService: SupplierService,private categoryService: CategoryService) { }
 

SortPrice($event:any){
  let icon = document.getElementById("asc-desc1");
  if(icon.className === "fas fa-angle-down"){
    icon.className ="fas fa-angle-up";
    this.homeService.getByPriceAsc().subscribe(data => {
    this.home = data;
  });
  }else{
    icon.className ="fas fa-angle-down"
    this.homeService.getByPriceDesc().subscribe(data => {
      this.home = data;
    });
  };
  
}
// model = new Newproduct(null,new Category( this.value,"name"),null,null,false,new Supplier(null,null),null);


onSubmit() {
  // TODO: Use EventEmitter with form value
  // console.warn(this.profileForm.value);
}
SortSale($event:any){
  let icon = document.getElementById("asc-desc2");
  if(icon.className === "fas fa-angle-down"){
    icon.className ="fas fa-angle-up";
    this.homeService.getBySaleAsc().subscribe(data => {
    this.home = data;
  });
  }else{
    icon.className ="fas fa-angle-down"
    this.homeService.getBySaleDesc().subscribe(data => {
      this.home = data;
    });
  };
  
}
SortDiscount($event:any){
  let icon = document.getElementById("asc-desc3");
  if(icon.className === "fas fa-angle-down"){
    icon.className ="fas fa-angle-up";
    this.homeService.getByDiscountAsc().subscribe(data => {
    this.home = data;
  });
  }else{
    icon.className ="fas fa-angle-down"
    this.homeService.getByDiscountDesc().subscribe(data => {
      this.home = data;
    });
  };
  
}


ngOnInit() {
  this.supplierService.getAll().subscribe(data => {
    this.suppliers = data;
  });
  
    this.homeService.getAll().subscribe(data => {
    this.home = data;
  });
  this.categoryService.getAll().subscribe(data => {
    this.categories = data;
  });
  
}

}

【问题讨论】:

  • 不要将 ngmodel 与 reactiveForms 一起使用。在 formGroup 上使用 setValuepatchValue
  • @AndreElrico 如果可以的话,我想要一个例子

标签: javascript html angular


【解决方案1】:

不要混淆响应式表单驱动的模板。您可以阅读更多信息here

当您在同一个视图中使用 3 个 API 时,您可以等待它们全部响应,然后执行您想要的逻辑。这可以通过将 observables 设置为对象(rxjs forkJoin

来完成
const observables = {
  suppliers: this.supplierService.getAll(),
  home: this.homeService.getAll(),
  categories: this.categoryService.getAll()
};

forkJoin(observables).subscribe({ suppliers, home, categories } => {
  this.suppliers = suppliers;
  this.home = home;
  this.categories = categories;
});

之后,使用 patchValue 更新表单:

updateProfile() {
  this.updateProduct.patchValue({
    id: this.home.id,
    productName: this.home.productName,
    category: this.home.category,
    fullPrice: this.home.fullPrice,
    salePrice: this.home.salePrice,
    availability: this.home.availability,
    supplier: this.home.supplier,
    discount: this.home.discount
  });
}

最后一件事,删除 selected 并为选项添加一个值,以便在修补值后选择它(最好有一个类别的 id 将它们设置为值)

<select class="form-control" formControlName="category" >
  <option [value]="home.category.categoryName" class="opt1" >{{home.category.categoryName}}</option>
  <option [value]="category.categoryName" *ngFor="let category of categories">{{category.categoryName}}</option>
</select>

现在当你要提交时,你可以通过表单读取值:

const formValues = this.updateProduct.value;
// This will contains all the values, you can access them by formValues.firstName ...etc

有关响应式表单的更多信息,您可以查看here

【讨论】:

  • 我相信你的意思是在响应到来之前初始值是未定义的。要解决此问题,您有两个选择:为所有使用 home 属性的元素添加安全导航运算符 ?:home?.productName 和 home?.category?.categoryName。或者,您可以在表单中添加一个NgIf,以便现在显示家庭尚未定义的时间,例如:*ngIf="home",并为用户显示一个加载器
  • 我一直在与您的答案作斗争,试图理解和实施它一个多小时。我的打字稿中出现了很多错误。这是我的堆栈闪电战stackblitz.com/github/RashellSmith/…
  • 我在上课时真的只使用了?。我的 ts 文件中的 home 引用了数组 home [] 因为我无法访问 home 对象的特征。
  • update-product.component.html 中,您可以看到表单值为{{ profileForm.value | json }}
  • 所以我很困惑。您能否添加服务的响应,以便我了解更多信息?您可以在调用 localhost 时将它们添加到 stackblitz 中,这样它就不起作用了。将它们添加为虚拟数据。
猜你喜欢
  • 1970-01-01
  • 2018-04-11
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 2019-06-18
  • 2020-03-13
  • 2018-04-26
  • 1970-01-01
相关资源
最近更新 更多