You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular组件传值异常:PrimeNG p-table的onLazyLoad回调未获取值

Angular组件传值与PrimeNG LazyLoad同步问题解决方案

问题说明

从A组件通过EventEmitter传递FloorCode到跳转后的B组件,B组件ngOnInit能接收值,但PrimeNG p-table的onLazyLoad回调loadAssets中selectedCurrentFloorCode始终为undefined,需确保loadAssets等待值更新后执行。


原代码回顾

A组件(AComponent)

import { Component } from '@angular/core';
import { MyService } from '../my-service.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-a',
  template: `
    <button (click)="sendCurrentFloorCode('FloorCode123')">Send Floor Code</button>
  `,
})
export class AComponent {
  constructor(private placeServices: MyService, private route: Router) {}

  sendCurrentFloorCode(floorCode: string) {
    this.placeServices.selectedFloorCode.emit(floorCode);
    this.route.navigate(['/inventory/list']);
  }
}

服务(MyService)

import { Injectable, EventEmitter } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MyService {
  selectedFloorCode = new EventEmitter<string>();
}

B组件(BComponent)

import { Component, OnInit } from '@angular/core';
import { MyService } from '../my-service.service';
import { LazyLoadEvent } from 'primeng/api';

@Component({
  selector: 'app-b',
  template: `
    <p-table
      #dt
      dataKey="id"
      styleClass="p-datatable-customers"
      [value]="allInventories.length > 0 || !loading ? allInventories : fakeData"
      [(selection)]="selectedInventories"
      [rowHover]="true"
      [rows]="defaultState.rows"
      [showCurrentPageReport]="true"
      [rowsPerPageOptions]="[10, 25, 50]"
      [lazy]="true"
      (onLazyLoad)="loadAssets($event)"
      [paginator]="true"
      [totalRecords]="totalCount"
      [filterDelay]="1000"
      (onRowSelect)="onRowSelect($event)"
      (onRowUnselect)="onRowUnselect($event)"
      (onHeaderCheckboxToggle)="selectUnselectAllRows($event)"
      (onContextMenuSelect)="onContextMenuSelect($event)"
      [contextMenu]="cm"
      stateStorage="session"
      [stateKey]="stateKey"
      (onStateSave)="onStateSave($event)"
      (onStateRestore)="onStateRestore($event)"
      [currentPageReportTemplate]="
        loading
          ? 'Yükleniyor'
          : 'Gösterilen satırlar: {first} ile {last} arası. Toplam: {totalRecords} satır.'
      "
    >
      <!-- Other HTML content of your p-table -->
    </p-table>
  `,
})
export class BComponent implements OnInit {
  selectedCurrentFloorCode: string | undefined;

  constructor(private placeServices: MyService) {}

  ngOnInit() {
    this.placeServices.selectedFloorCode.subscribe((value) => {
      this.selectedCurrentFloorCode = value;
      console.log('Received Data in B:', this.selectedCurrentFloorCode);
    });
  }

  loadAssets(event: LazyLoadEvent) {
    console.log('Inside loadAssets:', this.selectedCurrentFloorCode);
    console.log('LazyLoadEvent:', event);
    // Asset loading logic here
  }
}

解决方案

方案1:用BehaviorSubject替代EventEmitter(推荐)

EventEmitter设计用于组件输出,服务中应使用RxJS的BehaviorSubject,它能保存当前值,新订阅者可立即获取最新值,同时缓存未就绪时的LazyLoad事件。

修改MyService

import { Injectable, BehaviorSubject } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MyService {
  // 私有Subject存储值,对外暴露Observable
  private selectedFloorCodeSource = new BehaviorSubject<string | undefined>(undefined);
  selectedFloorCode$ = this.selectedFloorCodeSource.asObservable();

  // 提供方法更新值
  setSelectedFloorCode(floorCode: string) {
    this.selectedFloorCodeSource.next(floorCode);
  }
}

修改AComponent

sendCurrentFloorCode(floorCode: string) {
  this.placeServices.setSelectedFloorCode(floorCode);
  this.route.navigate(['/inventory/list']);
}

修改BComponent

import { Component, OnInit, OnDestroy } from '@angular/core';
import { MyService } from '../my-service.service';
import { LazyLoadEvent } from 'primeng/api';
import { Subscription } from 'rxjs';

@Component({
  // 模板保持不变
})
export class BComponent implements OnInit, OnDestroy {
  selectedCurrentFloorCode: string | undefined;
  private floorCodeSubscription!: Subscription;
  private hasFloorCode = false;
  private pendingLazyLoadEvent: LazyLoadEvent | undefined;

  constructor(private placeServices: MyService) {}

  ngOnInit() {
    this.floorCodeSubscription = this.placeServices.selectedFloorCode$.subscribe((value) => {
      this.selectedCurrentFloorCode = value;
      this.hasFloorCode = !!value;
      console.log('Received Data in B:', this.selectedCurrentFloorCode);
      
      // 如果有未处理的LazyLoad事件,立即执行
      if (this.pendingLazyLoadEvent) {
        this.loadAssets(this.pendingLazyLoadEvent);
        this.pendingLazyLoadEvent = undefined;
      }
    });
  }

  loadAssets(event: LazyLoadEvent) {
    if (!this.hasFloorCode) {
      // 未获取到FloorCode,缓存事件
      this.pendingLazyLoadEvent = event;
      return;
    }

    // 安全使用selectedCurrentFloorCode执行加载逻辑
    console.log('Inside loadAssets:', this.selectedCurrentFloorCode);
    console.log('LazyLoadEvent:', event);
    // 你的资源加载代码
  }

  ngOnDestroy() {
    // 销毁订阅防止内存泄漏
    this.floorCodeSubscription.unsubscribe();
  }
}

方案2:手动触发表格加载

在B组件获取到FloorCode后,手动调用loadAssets或重置表格,确保值就绪后再执行加载。

修改BComponent

import { Component, OnInit, ViewChild } from '@angular/core';
import { MyService } from '../my-service.service';
import { LazyLoadEvent } from 'primeng/api';
import { Table } from 'primeng/table';

@Component({
  // 模板保持不变
})
export class BComponent implements OnInit {
  selectedCurrentFloorCode: string | undefined;
  @ViewChild('dt') table!: Table;
  private isTableInitialized = false;

  constructor(private placeServices: MyService) {}

  ngOnInit() {
    this.placeServices.selectedFloorCode.subscribe((value) => {
      this.selectedCurrentFloorCode = value;
      console.log('Received Data in B:', this.selectedCurrentFloorCode);
      
      // 表格已初始化时,手动触发加载
      if (this.isTableInitialized) {
        this.table.reset(); // 重置表格会触发onLazyLoad
      }
    });
  }

  loadAssets(event: LazyLoadEvent) {
    if (!this.selectedCurrentFloorCode) {
      // 标记表格已初始化,等待后续手动触发
      this.isTableInitialized = true;
      return;
    }

    console.log('Inside loadAssets:', this.selectedCurrentFloorCode);
    console.log('LazyLoadEvent:', event);
    // 你的资源加载代码
  }
}

方案3:路由传参(适合一次性跳转传值)

如果只是跳转时传递一次性参数,用路由查询参数更可靠,无需依赖服务订阅。

修改AComponent

sendCurrentFloorCode(floorCode: string) {
  this.route.navigate(['/inventory/list'], { queryParams: { floorCode } });
}

修改BComponent

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { LazyLoadEvent } from 'primeng/api';
import { Table } from 'primeng/table';

@Component({
  // 模板保持不变
})
export class BComponent implements OnInit {
  selectedCurrentFloorCode: string | undefined;
  @ViewChild('dt') table!: Table;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.queryParams.subscribe(params => {
      this.selectedCurrentFloorCode = params['floorCode'];
      console.log('Received Data in B:', this.selectedCurrentFloorCode);
      
      // 拿到参数后触发表格加载
      if (this.selectedCurrentFloorCode) {
        this.table.reset();
      }
    });
  }

  loadAssets(event: LazyLoadEvent) {
    if (!this.selectedCurrentFloorCode) return;

    console.log('Inside loadAssets:', this.selectedCurrentFloorCode);
    console.log('LazyLoadEvent:', event);
    // 你的资源加载代码
  }
}

内容的提问来源于stack exchange,提问作者ekinkoseoglu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:57:32