自动完成搜索过滤器不适用于角度中动态添加的输入字段

问题描述 投票:0回答:1

我正在开发计费模块,该模块具有动态添加的输入字段。在这里,我使用自动完成搜索过滤器来动态添加输入字段(产品名称)。

但是,如果有一个产品名称字段,自动完成搜索工作正常。当我添加多个产品名称详细信息时,只有最后添加的字段可以正常工作。当我尝试更改以前的产品名称字段时,它不起作用。

以下html代码

<form [formGroup]="productFormarray" (ngSubmit)="onSubmit()">
<div class="reg-right">
    <div class="formGroup">
        <label for="customername" class="form-label">Customer Name</label>
        <input type="text" class="form-control" id="customername" placeholder="Customer Name"
            formControlName="customername">
    </div>
    <div class="formGroup" class="formGroup" formArrayName="productdetails">
        <div class="table-responsive">
            <table class="table table-bordered" style="margin-top: 20px;">
                <thead>
                    <tr>
                        <td style="width:40%">
                            Product Name
                        </td>
                        <td style="width:15%">
                            Quantity
                        </td>
                        <td style="width:15%">
                            Price
                        </td>
                        <td style="width:15%">
                            Gst
                        </td>
                        <td>
                        </td>
                    </tr>
                </thead>
                <tr *ngFor="let product of productdetailsarray.controls; let i=index" [formGroupName]="i">
                    <td>
                        <div class="formGroup">
                            <input formControlName="productname" matInput type="text" [matAutocomplete]="auto"
                                class="form-control" [formControl]="formcontrol" />
                            <mat-autocomplete #auto="matAutocomplete">
                                <mat-option *ngFor="let product of filteroptions | async" [value]="product">
                                    {{product}}
                                </mat-option>
                            </mat-autocomplete>
                        </div>
                    </td>
                    <td>
                        <div class="formGroup">
                            <select class="form-control" id="quantit" formControlName="quantit" name="quantit">
                                <option *ngFor="let quantity of quantitylist" [ngValue]="quantity">
                                    {{quantity}}
                                </option>
                            </select>
                        </div>
                    </td>
                    <td>
                        <div class="formGroup">
                            <input type="text" class="form-control" id="price" formControlName="price"
                                placeholder="Price " readonly name="price">
                        </div>
                    </td>
                    <td>
                        <div class="formGroup">
                            <input type="text" class="form-control" id="gst" formControlName="gst" placeholder="Gst"
                                name="gst" readonly>
                        </div>
                    </td>
                    <td>
                        <a type="button" class="form-control btn btn-primary" style="background-color: red;"
                            (click)="removeProduct(i)">Remove (-)</a>
                    </td>
                </tr>
            </table>
        </div>
        <a type="button" class="btn btn-secondary" style="background-color: green;"
            (click)="addNewProduct()">Add(+)</a>
        <br />
    </div>
    <br />
    <br />
    <div class="row">
        <div class="col-md-6">
        </div>
        <div class="col-md-6">
            <div class="formGroup">
                <label for="totalprice" class="form-label" style="margin-top: 10pt;">Total Product Price</label>
                <input type="text" class="form-control form-control1" id="totalprice" formControlName="totalprice"
                    placeholder="totalprice" name="totalprice" style="margin-left: 20pt; float:right" readonly>
            </div>
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</div>

下面是打字稿代码

import { Component, OnInit, ViewChild } from '@angular/core';
import { FormGroup, FormControl, FormArray, FormBuilder, NgForm, Validators } from '@angular/forms'
import { EMPTY, Observable, map, of, startWith } from 'rxjs';
import { toArray } from 'rxjs';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit 
 {
  productFormarray: any;
  quantitylist = [0.5, 1, 1.5];
  items!: FormArray;
  totalGstPrice: number = 0;
  totalProductPrice: number = 0;
  productlist = [{ productname: "apple", price: 10, gst: 10 }, { productname: "orange", price: 20, gst: 12 }, { productname: "lemon", price: 30, gst: 20 }];
  productlistss = ['apple', 'lemon', 'orange'];
  filteroptions!: Observable<string[]>;
  formcontrol = new FormControl('');

  constructor(private fb: FormBuilder) {
    this.productFormarray = new FormGroup({
      customername: new FormControl('', Validators.required),
      productdetails: new FormArray([]),
      remember: new FormControl('true'),
      totalprice: new FormControl(''),
    })
  }

  private _filter(value: string): string[] {
    const searchvalue = value.toLocaleLowerCase();
    return this.productlistss.filter(option => option.toLocaleLowerCase().includes(searchvalue));
  }

  onProductChange(selectedProductName: string, index: number) {
    const selectedProduct = this.productlist.find(
      (product) => product.productname === selectedProductName
    );
    if (selectedProduct) {
      const productDetailsArray = this.productFormarray.get(
        'productdetails'
      ) as FormArray;
      if (productDetailsArray && productDetailsArray.at(index)) {
        const quantityControl = productDetailsArray.at(index).get('quantit');
        if (quantityControl) {
          const quantity = quantityControl.value;
          const price = selectedProduct.price * quantity;
          const priceControl = productDetailsArray.at(index).get('price');
          if (priceControl) {
            priceControl.setValue(price);
          }
        }
      }
    }
  }

  onQuantityChange(selectedQuantity: number, index: number) {
    const productDetailsArray = this.productFormarray.get(
      'productdetails'
    ) as FormArray;
    if (productDetailsArray && productDetailsArray.at(index)) {
      const productNameControl = productDetailsArray.at(index).get('productname');
      if (productNameControl) {
        const selectedProductName = productNameControl.value;
        const selectedProduct = this.productlist.find(
          (product) => product.productname === selectedProductName
        );
        if (selectedProduct) {
          const price = selectedProduct.price * selectedQuantity;
          const priceControl = productDetailsArray.at(index).get('price');
          if (priceControl) {
            priceControl.setValue(price);
          }
        }
      }
    }
  }

  onPriceChange(selectedQuantity: number, index: number) {
    const productDetailsArray = this.productFormarray.get('productdetails') as FormArray;
    if (productDetailsArray && productDetailsArray.at(index)) {
      const productNameControl = productDetailsArray.at(index).get('productname');
      if (productNameControl) {
        const selectedProductName = productNameControl.value;
        const selectedProduct = this.productlist.find(
          (product) => product.productname === selectedProductName
        );
        if (selectedProduct) {
          const priceControl = productDetailsArray.at(index).get('price');
          const gst = ((selectedProduct.gst * priceControl?.value) / 100);
          const gstControl = productDetailsArray.at(index).get('gst');
          gstControl?.setValue(gst);
        }
      }
    }
  }

  addNewProduct() {
    this.items = this.productFormarray.get('productdetails') as FormArray;
    const newProduct = this.createNewProduct();
    this.items.push(newProduct);
    const indexvalue = this.items.length - 1;
    this.productFormarray.get('productdetails').controls[indexvalue].get('quantit').setValue(this.quantitylist[1]);
    const productNameControl = newProduct.get('productname');
    if (productNameControl) {
      this.filteroptions = productNameControl.valueChanges.pipe(startWith(''), map(value => this._filter(value)));
      console.log('filteroption--- = ' + this.filteroptions);
      productNameControl.valueChanges.subscribe(selectedProductName => {
        this.onProductChange(selectedProductName, indexvalue);
      }
      );
    }
    const quantityControl = newProduct.get('quantit');
    if (quantityControl) {
      quantityControl.valueChanges.subscribe(selectedQuantity => {
        this.onQuantityChange(selectedQuantity, indexvalue);
      })
    }
    const priceControl = newProduct.get('price');
    if (priceControl) {
      priceControl.valueChanges.subscribe((selectedProductName) =>
        this.onPriceChange(selectedProductName, indexvalue)
      );
    }
  }

  createNewProduct(): FormGroup {
    return new FormGroup({
      productname: new FormControl('', Validators.required),
      quantit: new FormControl('1', Validators.required),
      price: new FormControl('', Validators.required),
      gst: new FormControl('', Validators.required)
    })
  }

  removeProduct(index: any) {
    this.items = this.productFormarray.get('productdetails') as FormArray;
    this.items.removeAt(index);
  }
  get productdetailsarray() {
    return this.productFormarray.get('productdetails') as FormArray;
  }

  ngOnInit() {
    this.addNewProduct();
  }
  onSubmit() {
  }
}

有人可以帮我吗。

angular search filter autocomplete
1个回答
0
投票

不要选择

valueChanges
,这对于表单数组来说似乎很乏味,而是尝试以下方法,我们使用
(input)
事件监听输入更改,并使用
(opened)
(click)
事件重置自动完成,其中我们通过将字段作为参数传递给函数来重置输入的最新值,请参考下面的代码/stackblitz 供您参考!

ts

import { Component, OnInit } from '@angular/core';
import {
  FormsModule,
  ReactiveFormsModule,
  FormGroup,
  FormControl,
  FormArray,
  FormBuilder,
  Validators,
} from '@angular/forms';
import { AsyncPipe, CommonModule } from '@angular/common';
import {
  MatAutocomplete,
  MatAutocompleteModule,
} from '@angular/material/autocomplete';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { Observable, map, of, startWith } from 'rxjs';

/**
 * @title Highlight the first autocomplete option
 */
@Component({
  selector: 'autocomplete-auto-active-first-option-example',
  templateUrl: 'autocomplete-auto-active-first-option-example.html',
  styleUrl: 'autocomplete-auto-active-first-option-example.css',
  standalone: true,
  imports: [
    FormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatAutocompleteModule,
    ReactiveFormsModule,
    AsyncPipe,
    CommonModule,
  ],
})
export class AutocompleteAutoActiveFirstOptionExample implements OnInit {
  productFormarray: any;
  quantitylist = [0.5, 1, 1.5];
  items!: FormArray;
  totalGstPrice: number = 0;
  totalProductPrice: number = 0;
  productlist = [
    { productname: 'apple', price: 10, gst: 10 },
    { productname: 'orange', price: 20, gst: 12 },
    { productname: 'lemon', price: 30, gst: 20 },
  ];
  productlistss = ['apple', 'lemon', 'orange'];
  filteroptions!: Observable<string[]>;

  resetFilters() {
    this.filteroptions = of(this.productlistss);
  }
  constructor(private fb: FormBuilder) {
    this.productFormarray = new FormGroup({
      customername: new FormControl('', Validators.required),
      productdetails: new FormArray([]),
      remember: new FormControl('true'),
      totalprice: new FormControl(''),
    });
  }

  private _filter(value: string): string[] {
    const searchvalue = value.toLocaleLowerCase();
    return this.productlistss.filter((option) =>
      option.toLocaleLowerCase().includes(searchvalue)
    );
  }

  onProductChange(event: any, index: number) {
    const selectedProductName = event?.option?.value;
    const selectedProduct = this.productlist.find(
      (product) => product.productname === selectedProductName
    );
    if (selectedProduct) {
      const productDetailsArray = this.productFormarray.get(
        'productdetails'
      ) as FormArray;
      if (productDetailsArray && productDetailsArray.at(index)) {
        const quantityControl = productDetailsArray.at(index).get('quantit');
        if (quantityControl) {
          const quantity = quantityControl.value;
          const price = selectedProduct.price * quantity;
          const priceControl = productDetailsArray.at(index).get('price');
          if (priceControl) {
            priceControl.setValue(price);
          }
        }
      }
    }
    this.onPriceChange(index);
  }

  onQuantityChange(event: any, index: number) {
    const selectedQuantity = +(event || 0);
    const productDetailsArray = this.productFormarray.get(
      'productdetails'
    ) as FormArray;
    if (productDetailsArray && productDetailsArray.at(index)) {
      const productNameControl = productDetailsArray
        .at(index)
        .get('productname');
      if (productNameControl) {
        const selectedProductName = productNameControl.value;
        const selectedProduct = this.productlist.find(
          (product) => product.productname === selectedProductName
        );
        if (selectedProduct) {
          const price = selectedProduct.price * selectedQuantity;
          const priceControl = productDetailsArray.at(index).get('price');
          if (priceControl) {
            priceControl.setValue(price);
          }
        }
      }
    }
    this.onPriceChange(index);
  }

  onPriceChange(index: number) {
    const productDetailsArray = this.productFormarray.get(
      'productdetails'
    ) as FormArray;
    if (productDetailsArray && productDetailsArray.at(index)) {
      const productNameControl = productDetailsArray
        .at(index)
        .get('productname');
      if (productNameControl) {
        const selectedProductName = productNameControl.value;
        const selectedProduct = this.productlist.find(
          (product) => product.productname === selectedProductName
        );
        if (selectedProduct) {
          const priceControl = productDetailsArray.at(index).get('price');
          const gst = (selectedProduct.gst * priceControl?.value) / 100;
          const gstControl = productDetailsArray.at(index).get('gst');
          gstControl?.setValue(gst);
        }
      }
    }
  }

  addNewProduct() {
    this.items = this.productFormarray.get('productdetails') as FormArray;
    const newProduct = this.createNewProduct();
    this.items.push(newProduct);
    const indexvalue = this.items.length - 1;
    this.productFormarray
      .get('productdetails')
      .controls[indexvalue].get('quantit')
      .setValue(this.quantitylist[1]);
    // const productNameControl = newProduct.get('productname');
    // if (productNameControl) {
    //   productNameControl.valueChanges.subscribe((selectedProductName) => {
    //     this.onProductChange(selectedProductName, indexvalue);
    //   });
    // }
    // const quantityControl = newProduct.get('quantit');
    // if (quantityControl) {
    //   quantityControl.valueChanges.subscribe((selectedQuantity) => {
    //     this.onQuantityChange(selectedQuantity, indexvalue);
    //   });
    // }
    // const priceControl = newProduct.get('price');
    // if (priceControl) {
    //   priceControl.valueChanges.subscribe((selectedProductName) =>
    //     this.onPriceChange(selectedProductName, indexvalue)
    //   );
    // }
  }

  createNewProduct(): FormGroup {
    return new FormGroup({
      productname: new FormControl('', Validators.required),
      quantit: new FormControl('1', Validators.required),
      price: new FormControl('', Validators.required),
      gst: new FormControl('', Validators.required),
    });
  }

  removeProduct(index: any) {
    this.items = this.productFormarray.get('productdetails') as FormArray;
    this.items.removeAt(index);
  }
  get productdetailsarray() {
    return this.productFormarray.get('productdetails') as FormArray;
  }

  ngOnInit() {
    this.addNewProduct();
    console.log('filteroption--- = ' + this.filteroptions);
  }

  performFiltering(input: any) {
    if (input.value) {
      this.filteroptions = of(this._filter(input.value));
    } else {
      this.filteroptions = of(this.productlistss);
    }
  }

  clicked(input: any) {
    this.filteroptions = of(this.productlistss);
    if (input.value) {
      this.performFiltering(input);
    }
  }
  onSubmit() {}
}

html

<form [formGroup]="productFormarray" (ngSubmit)="onSubmit()">
  <div class="reg-right">
    <div class="formGroup">
      <label for="customername" class="form-label">Customer Name</label>
      <input
        type="text"
        class="form-control"
        id="customername"
        placeholder="Customer Name"
        formControlName="customername"
      />
    </div>
    <div class="formGroup" formArrayName="productdetails">
      <div class="table-responsive">
        <table class="table table-bordered" style="margin-top: 20px">
          <thead>
            <tr>
              <td style="width: 40%">Product Name</td>
              <td style="width: 15%">Quantity</td>
              <td style="width: 15%">Price</td>
              <td style="width: 15%">Gst</td>
              <td></td>
            </tr>
          </thead>
          <tr
            *ngFor="let product of productdetailsarray.controls; let i=index"
            [formGroupName]="i"
          >
            <td>
              <div class="formGroup">
                <input
                  formControlName="productname"
                  [id]="'productname_' + i"
                  [name]="'productname_' + i"
                  matInput
                  #input
                  type="text"
                  [matAutocomplete]="auto"
                  class="form-control"
                  (click)="clicked(input)"
                  (input)="performFiltering(input)"
                  (opened)="performFiltering(input)"
                />
                <mat-autocomplete
                  #auto="matAutocomplete"
                  (optionSelected)="onProductChange($event, i)"
                >
                  <mat-option
                    *ngFor="let product of filteroptions | async"
                    [value]="product"
                  >
                    {{product}}
                  </mat-option>
                </mat-autocomplete>
              </div>
            </td>
            <td>
              <div class="formGroup">
                <select
                  #mySelect
                  class="form-control"
                  [id]="'quantit_' + i"
                  [name]="'quantit_' + i"
                  formControlName="quantit"
                  (change)="onQuantityChange(mySelect.value, i)"
                >
                  <option
                    *ngFor="let quantity of quantitylist"
                    [value]="quantity"
                  >
                    {{quantity}}
                  </option>
                </select>
              </div>
            </td>
            <td>
              <div class="formGroup">
                <input
                  type="text"
                  class="form-control"
                  [id]="'price_' + i"
                  [name]="'price_' + i"
                  formControlName="price"
                  placeholder="Price "
                  readonly
                />
              </div>
            </td>
            <td>
              <div class="formGroup">
                <input
                  type="text"
                  class="form-control"
                  id="gst"
                  formControlName="gst"
                  placeholder="Gst"
                  name="gst"
                  readonly
                />
              </div>
            </td>
            <td>
              <a
                type="button"
                class="form-control btn btn-primary"
                style="background-color: red"
                (click)="removeProduct(i)"
                >Remove (-)</a
              >
            </td>
          </tr>
        </table>
      </div>
      <a
        type="button"
        class="btn btn-secondary"
        style="background-color: green"
        (click)="addNewProduct()"
        >Add(+)</a
      >
      <br />
    </div>
    <br />
    <br />
    <div class="row">
      <div class="col-md-6"></div>
      <div class="col-md-6">
        <div class="formGroup">
          <label for="totalprice" class="form-label" style="margin-top: 10pt"
            >Total Product Price</label
          >
          <input
            type="text"
            class="form-control form-control1"
            id="totalprice"
            formControlName="totalprice"
            placeholder="totalprice"
            name="totalprice"
            style="margin-left: 20pt; float: right"
            readonly
          />
        </div>
      </div>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
  </div>
</form>

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.