如何在Angular服务数据变更时动态重新渲染组件
解决方案:Angular侧边栏自动更新菜单状态
问题根源
当前实现的核心问题:
- 侧边栏的
empresas数组仅在ngOnInit时从environment.usuario.empresas初始化,添加新公司后未同步更新该数组 rerender()方法仅设置visible=true并手动触发变更检测,但未更新核心数据empresas,也未同步environment中的用户公司列表- 服务仅发送空事件,未携带新公司信息,无法让侧边栏获取最新状态
具体修改步骤
1. 优化服务:传递新公司数据(高效方案)
修改EmpresasService,让事件携带新创建的公司对象,避免侧边栏重复请求数据:
import { Subject } from 'rxjs'; export class EmpresasService { private reRender = new Subject<any>(); reRender$ = this.reRender.asObservable(); emitFunction(newCompany?: any) { this.reRender.next(newCompany); } }
2. 更新公司创建组件的事件触发
在Empresa.component.ts的_store方法中,将新创建的公司对象传递给服务:
private async _store() { try { await this._spinner.show(); const objeto = await this.empresas_service.store(this.form.value); this._toastr_service.success('Company successfully added!'); this.empresas_service.emitFunction(objeto); // 传递新公司数据 this._form_directive.resetForm(); this._inicializaForm(); this.close(); await this._spinner.hide(); } catch (error: any) { this._toastr_service.error(error.error); await this._spinner.hide(); } }
3. 修复侧边栏的更新逻辑
确保ChangeDetectorRef正确注入,同步更新数据源和组件状态:
import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { environment } from 'src/environments/environment'; /* Other imports */ export class SidebarComponent implements OnInit { nombre: string = ''; nombre_empresa: string = ''; empresas: any[] = []; public visible: boolean = true; constructor( private _empresas_service: EmpresasService, private _cambios_empresas: ChangeDetectorRef ) { this._empresas_service.reRender$.subscribe((newCompany) => { this.rerender(newCompany); }); } rerender(newCompany?: any) { // 更新环境变量中的公司列表 if (newCompany) { environment.usuario.empresas.push(newCompany); } // 同步组件内的数据源(用扩展运算符触发变更检测) this.empresas = [...environment.usuario.empresas]; // 更新显示状态 this.visible = this.empresas.length > 0; // 标记组件需要变更检测 this._cambios_empresas.markForCheck(); // 如果需要更新当前选中的公司名称 if (this.visible) { this.nombre_empresa = this.empresas.find(e => e.id == environment.empresa_id)?.nombre || ''; } } async ngOnInit() { this.nombre = environment.usuario.nombre; this.empresas = [...environment.usuario.empresas]; this.visible = this.empresas.length > 0; if (this.visible) { this.nombre_empresa = this.empresas.find(e => e.id == environment.empresa_id)?.nombre || ''; } await this._empresas_service.indexPanelAdmin(); this.menuItems = ROUTES.filter(menuItem => menuItem); if (window.matchMedia(`(min-width: 960px)`).matches && !this.isMac()) { const elemSidebar = <HTMLElement>document.querySelector('.sidebar .sidebar-wrapper'); this.ps = new PerfectScrollbar(elemSidebar); } } }
4. 简化模板条件(可选)
模板逻辑可直接依赖empresas.length,无需额外维护visible变量:
<!-- Sidebar HTML snippet --> <li routerLinkActive="active" class="nav-item" *ngIf="empresas.length === 0"> <a routerLink="/empresas" class="nav-link"> <i class="material-icons">dashboard</i> <p>Empresas</p> </a> </li> <!-- Rest of the menu items --> <ng-container *ngIf="empresas.length > 0"> <li routerLinkActive="active" *ngFor="let menuitem of menuItems" class="nav-item"> <a [routerLink]="[menuitem.path]" *ngIf="menuitem.type === 'link'" class="nav-link"> <i class="material-icons">{{menuitem.icontype}}</i> <p>{{menuitem.title}}</p> </a> </li> </ng-container>
关键说明
- 核心是同步更新组件的数据源:侧边栏UI依赖
empresas数组,必须确保该数组在公司创建后被更新 - 使用
markForCheck()替代detectChanges():更符合Angular变更检测策略,仅标记组件需要检测而非强制立即检测 - 建议避免用
environment存储动态数据:如果用户信息需频繁更新,可将其移至专门的用户服务中管理,更易维护和同步
内容的提问来源于stack exchange,提问作者Alejandro Alonso
相关产品推荐
相关产品推荐

