Angular查询后如何为对象赋值?消息与地址对象关联问题
问题描述
我有个Message类,里面包含Addresses数组。需求很明确:
- 页面一打开就查所有待处理消息
- 用户点开某条消息的地址标签页时,再去查这条消息对应的
Addresses
但现在Addresses和Messages是分开管理的独立对象,折腾出三种问题:
- 数据都对,但打开第一个消息的标签页时,所有消息的地址都被查完了
- 只有最后一条消息的地址是对的,前面的全被改成和最后一条一样
- 功能正常,但每条消息得点按钮才能查地址
现有代码如下:
getMessages(): void { let request: GetPendingMessagesRequest; this.isLoadingResultSubject.next(true); this.messagesQuery$.next(); this.messagesQuery$.complete(); this.messagesQuery$ = new Subject(); this.queryDispatcher.dispatch(request, null, this.messagesQuery$) .pipe(takeUntil(this.destroy$)) .subscribe({ next: (getResponse: GetPendingMessagesResponse) => { this.messagesSubject.next(getResponse.messages); this.isLoadingResultSubject.next(false); }, error: () => this.MessagesService.delete() }); } getAddresses(ObjektId: string | number, documentId: string | number, document: Document): void { let request: GetAddressesRequest; request = new GetAddressesRequest( ObjektId, documentId, ); this.addressesQuery$.next(); this.addressesQuery$ = new Subject(); this.queryDispatcher.dispatch(request, null, this.addressesQuery$) .pipe(takeUntil(this.destroy$)) .subscribe({next:(getaddressesResponse: GetAddressesResponse) => { this.addressesSubject.next(getaddressesResponse.addresses) }, error: () => this.AdressesService.delete()}); }
问题根源
- 用了全局的
addressesSubject,所有消息共享同一组地址数据,查最后一条时会覆盖之前的,导致第二种问题 - 如果不小心循环触发了所有消息的地址查询,就会出现第一种问题
- 没把地址查询和标签页打开事件绑定,也没关联到具体消息,所以只能靠按钮触发
解决方案
核心就是把Addresses和对应的Message绑在一起,别用全局状态单独存,按下面步骤改:
1. 给Message加地址相关字段
先给Message类(或接口)加两个字段,用来存地址和标记加载状态:
interface Message { // 你原来的字段 objektId: string | number; documentId: string | number; // 新增字段 addresses?: Address[]; // 存当前消息的地址 isAddressesLoading: boolean; // 标记地址是否在加载 }
2. 初始化消息时设置状态
获取消息列表后,给每条消息初始化地址相关状态:
getMessages(): void { let request: GetPendingMessagesRequest; this.isLoadingResultSubject.next(true); this.messagesQuery$.next(); this.messagesQuery$.complete(); this.messagesQuery$ = new Subject(); this.queryDispatcher.dispatch(request, null, this.messagesQuery$) .pipe(takeUntil(this.destroy$)) .subscribe({ next: (getResponse: GetPendingMessagesResponse) => { // 每条消息默认没加载地址,也没有地址数据 const initializedMessages = getResponse.messages.map(msg => ({ ...msg, isAddressesLoading: false, addresses: undefined })); this.messagesSubject.next(initializedMessages); this.isLoadingResultSubject.next(false); }, error: () => this.MessagesService.delete() }); }
3. 修改地址查询方法,绑定到具体消息
别再用全局的addressesSubject了,查到地址后直接更新对应的消息对象:
// 先存一份当前的消息列表,方便后续更新 private currentMessages: Message[] = []; // 订阅messagesSubject,同步当前消息列表 constructor() { this.messagesSubject.pipe(takeUntil(this.destroy$)).subscribe(messages => { this.currentMessages = messages; }); } getAddresses(targetMessage: Message): void { // 已经加载过或者正在加载,直接返回,避免重复请求 if (targetMessage.addresses || targetMessage.isAddressesLoading) return; // 标记这条消息的地址正在加载 const updatedMessages = this.currentMessages.map(msg => msg.objektId === targetMessage.objektId && msg.documentId === targetMessage.documentId ? {...msg, isAddressesLoading: true} : msg ); this.messagesSubject.next(updatedMessages); const request = new GetAddressesRequest( targetMessage.objektId, targetMessage.documentId, ); this.addressesQuery$.next(); this.addressesQuery$ = new Subject(); this.queryDispatcher.dispatch(request, null, this.addressesQuery$) .pipe(takeUntil(this.destroy$)) .subscribe({ next: (response: GetAddressesResponse) => { // 查到地址后,更新这条消息的地址并取消加载状态 const updatedMessages = this.currentMessages.map(msg => msg.objektId === targetMessage.objektId && msg.documentId === targetMessage.documentId ? {...msg, addresses: response.addresses, isAddressesLoading: false} : msg ); this.messagesSubject.next(updatedMessages); }, error: () => { this.AdressesService.delete(); // 出错了也要取消加载状态 const updatedMessages = this.currentMessages.map(msg => msg.objektId === targetMessage.objektId && msg.documentId === targetMessage.documentId ? {...msg, isAddressesLoading: false} : msg ); this.messagesSubject.next(updatedMessages); } }); }
4. 绑定标签页打开事件
在页面模板里,给消息的地址标签页打开事件绑定getAddresses,把当前消息传进去:
<!-- 示例模板,根据你用的UI框架调整 --> <ng-container *ngFor="let message of messages$ | async"> <tab-group (tabChange)="handleTabChange(message, $event)"> <!-- 其他标签页 --> <tab label="地址"> <div *ngIf="message.isAddressesLoading">加载中...</div> <div *ngIf="message.addresses"> <!-- 这里渲染你的地址列表 --> </div> </tab> </tab-group> </ng-container>
// 组件里的事件处理函数 handleTabChange(message: Message, event: any): void { // 判断是不是地址标签页被打开了,根据实际情况调整判断逻辑 if (event.tab.label === '地址') { this.getAddresses(message); } }
这样改完后:
- 每条消息的地址数据和自己绑定,不会互相覆盖
- 只有用户打开某条消息的地址标签页时,才会触发这条消息的地址查询
- 自动处理加载状态,不用额外点按钮
内容的提问来源于stack exchange,提问作者Zulumaster
相关产品推荐
相关产品推荐

