数组仍未定义,即使在subscribe方法中分配

In my angular app the array productLocations is assigned in ngOnInit method in subscription and later on used in a method but it still is undefined. From searching on Stackoverflow everyone is saying to move assignment in subscription. It is already in subscription but I receive error. How to correctly execute things in sequence?

ERROR TypeError: Cannot read property 'forEach' of undefined
    at AddProductComponent.populateProductLocation

组件文件

export class AddProductComponent implements OnInit, OnDestroy {

  form: FormGroup;
  productManufacturerOptions: ProductManufacturer[] = [];
  filteredProductManufacturerOptions: Observable<ProductManufacturer[]>;
  productModelOptions: ProductModel[] = [];
  filteredProductModelOptions: Observable<ProductModel[]>;
  productCategoryOptions: ProductCategory[] = [];
  filteredProductCategoryOptions: Observable<ProductCategory[]>;

  product: Product = new Product();
  branches: Branch[] = [];
  productLocations: ProductLocation[];
  productPrices: ProductPrice[];
  priceLists: PriceList[] = [];
  editMode = false;
  private _unsubscribeAll: Subject<any>;
  fileToUpload: File = null;

  constructor(
    private http: HttpClient,
    private _formBuilder: FormBuilder,
    private productManufacturerService: ProductManufacturerService,
    private productModelService: ProductModelService,
    private productCategoryService: ProductCategoryService,
    private productService: ProductService,
    private branchService: BranchService,
    private router: Router,
    private route: ActivatedRoute,
    private _fuseProgressBarService: FuseProgressBarService,
    private priceListService: PriceListService,
    private cd: ChangeDetectorRef
  ) {
    this._unsubscribeAll = new Subject();
    this.initForm();
    if (this.route.snapshot.url[0].path == 'edit' && localStorage.getItem("editProductId")) {
      this.editMode = true;
    }
  }

  ngOnInit(): void {
    this._fuseProgressBarService.show();
    if (this.editMode) {
      this.productService.get(localStorage.getItem("editProductId"))
        .subscribe((result: any) => {
          this.product = new Product(result);
          console.log("Product", this.product);
          // this.productLocations = result.locations;
          this.productLocations = this.product.locations;
          this.productPrices = this.product.prices;
          this.populateUpdateData(result);
        });
    }

    forkJoin([this.productManufacturerService.getList(),
    this.productModelService.getList(),
    this.productCategoryService.getList(),
    this.branchService.getList(),
    this.priceListService.getList()
    ])
      .subscribe((results: any) => {
        this.productManufacturerOptions = results[0];
        this.productManufacturerStart();

        this.productModelOptions = results[1];
        this.productModelStart();

        this.productCategoryOptions = results[2];
        this.productCategoryStart();

        this.branches = results[3];
        this.priceLists = results[4];
      },
        error => { },
        () => {
          if (this.editMode) {
            this.populateProductLocations();
            this.populatePriceLists();
          }
          else {
            this.initProductLocations();
            this.initPriceLists();
          }
          this._fuseProgressBarService.hide();
        });
  }

  initForm() {
    this.form = this._formBuilder.group({
      id: [''],
      partNumber: ['', Validators.required],
      description: ['', Validators.required],
      replaceNumbers: this._formBuilder.array([]),
      manufacturer: [null, Validators.required],
      model: [null, Validators.required],
      category: [null, Validators.required],
      cost: ['', Validators.required],
      locations: this._formBuilder.array([]),
      prices: this._formBuilder.array([]),
      featuredImage: [null]
    });
  }

  initProductLocations() {
    this.branches.forEach(branch => {
      this.initProductLocation(branch)
    });
  }
  initProductLocation(branch) {
    const control = <FormArray>this.form.controls['locations'];
    var a = this._formBuilder.group({
      branch: [branch, Validators.required],
      location: [null, Validators.required],
      quantity: [null, Validators.required]
    });
    control.push(a);
  }
  populateProductLocations() {
    this.branches.forEach(branch => {
      this.populateProductLocation(branch)
    });
  }
  populateProductLocation(branch) {
    const control = <FormArray>this.form.controls['locations'];
    var a;
    var productLocationBranchIds = [];    
    this.productLocations.forEach(productLocation => {
      productLocationBranchIds.push(productLocation.branch.id)
    });
    console.log("ProdIDS", productLocationBranchIds);
    if (productLocationBranchIds.includes(branch.id)) {
      this.productLocations.forEach(productLocation => {
        if (branch.id == productLocation.branch.id) {
          a = this._formBuilder.group({
            branch: [productLocation.branch, Validators.required],
            location: [productLocation.location, Validators.required],
            quantity: [productLocation.quantity, Validators.required]
          });
        }
      });
    }
    else {
      console.log("In else");
      a = this._formBuilder.group({
        branch: [branch, Validators.required],
        location: [null, Validators.required],
        quantity: [null, Validators.required]
      });
    }
    control.push(a);
  }


  initPriceLists() {
    this.priceLists.forEach(priceList => {
      this.initPriceList(priceList)
    });
  }
  initPriceList(priceList) {
    const control = <FormArray>this.form.controls['prices'];
    var a = this._formBuilder.group({
      priceList: [priceList, Validators.required],
      price: [null, Validators.required]
    });
    control.push(a);
  }

  populatePriceLists() {
    this.priceLists.forEach(priceList => {
      this.populatePriceList(priceList)
    });
  }
  populatePriceList(priceList) {
    const control = <FormArray>this.form.controls['prices'];
    var a;
    var productPricesPriceListIds = [];
    this.productPrices.forEach(productPrice => {
      productPricesPriceListIds.push(productPrice.priceList.id)
    });
    if (productPricesPriceListIds.includes(priceList.id)) {
      this.productPrices.forEach(productPrice => {
        if (priceList.id == productPrice.priceList.id) {
          a = this._formBuilder.group({
            priceList: [productPrice.priceList, Validators.required],
            price: [productPrice.price, Validators.required]
          });
        }
      });
    }
    else {
      a = this._formBuilder.group({
        priceList: [priceList, Validators.required],
        price: [null, Validators.required]
      });
    }
    control.push(a);
  }

  get replaceNumbers(): FormArray {
    return this.form.get('replaceNumbers') as FormArray;
  }
  createReplaceNumber(): FormGroup {
    return this._formBuilder.group({
      partNumber: ['', Validators.required]
    });
  }
  addExistingReplaceNumber(value): FormGroup {
    return this._formBuilder.group({
      partNumber: [value, Validators.required]
    });
  }
  addReplaceNumber() {
    this.replaceNumbers.push(this.createReplaceNumber());
  }
  removeReplaceNumber(index: number) {
    this.replaceNumbers.removeAt(index);
  }

  populateUpdateData(product) {
    this.form.get('id').setValue(product.id);
    this.form.get('partNumber').setValue(product.partNumber);
    this.form.get('description').setValue(product.description);
    this.form.get('manufacturer').setValue(product.manufacturer);
    this.form.get('model').setValue(product.model);
    this.form.get('category').setValue(product.category);
    this.form.get('cost').setValue(product.cost);
    let rs = product.replaceNumbers;
    rs.forEach(element => {
      this.replaceNumbers.push(this.addExistingReplaceNumber(element.partNumber));
    });
  }

  ngOnDestroy(): void {
    this._unsubscribeAll.next();
    this._unsubscribeAll.complete();
  }
}
评论
  • 懒喵喵~
    懒喵喵~ 回复

    发生这种情况的原因可能是,以下块的执行时间比订阅的执行时间快:

              if (this.editMode) {
                this.populateProductLocations();
                this.populatePriceLists();
              }
    

    为了验证这一点,您可以在该块中以及要在其中分配值的订阅中执行console.log(或放置断点)。

    You should consider refactoring your code, so that this.populateProductLocations() comes after this.productLocations = this.product.locations; in the same code block, or waits until this.productService.get(localStorage.getItem("editProductId")) completes (maybe with a swithcMap, combineLatest or withLatestFrom).