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
相关产品推荐
相关产品推荐

