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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 04:15:15