Angular跨兄弟组件调用方法时*ngFor绑定数组更新后HTML不更新如何解决
问题根因
你当前写法的核心错误是直接在组件构造函数中注入其他组件类型获取实例:Angular的依赖注入容器默认管理的是服务类的单例,你注入的ProductPaginationComponent、ProductListComponent都不是页面上实际渲染的组件实例,而是全新创建的未挂载的组件对象,你修改的是这个游离对象的pagesNumbers属性,和页面上真实渲染的分页组件完全无关,所以页面不会有任何更新。
你在ngOnInit中调用方法生效,是因为该调用属于真实挂载的组件自身的生命周期逻辑,修改的是组件自身的属性,自然能触发页面更新。
推荐解决方案1:通过共同父组件中转(最适配当前场景)
你们两个兄弟组件都挂载在ProductListComponent的模板内,直接用父组件当通信中介是最简洁的方案:
步骤1:分类列表组件抛出选择事件
在CategoryListComponent中用Output+EventEmitter把选中的分类抛给父组件:
// CategoryListComponent 逻辑代码 import { Output, EventEmitter } from '@angular/core'; @Output() categorySelected = new EventEmitter<string|undefined>(); constructor(private categoryService: CategoryService) {} chooseCategory(cat?: string): void { this.categorySelected.emit(cat); }
步骤2:父组件监听事件,调用真实子组件方法
首先给父组件模板的子组件加模板引用变量,获取真实渲染的组件实例:
<!-- ProductListComponent 模板代码 --> <div class="row"> <div class="col-3"> <!-- 监听分类选择事件 --> <app-category-list (categorySelected)="onCategoryChange($event)"></app-category-list> </div> <div class="col-9"> <div class = "container"> <div class = "row"> <div class = "col-4" *ngFor="let prod of products; let i = index" > <app-product-view [prod]="prod" [count] = "i"></app-product-view> </div> </div> </div> <!-- 给分页组件加模板引用 #pagination --> <app-product-pagination #pagination></app-product-pagination> </div> </div>
父组件逻辑中处理事件:
// ProductListComponent 逻辑代码 import { ViewChild } from '@angular/core'; import { ProductPaginationComponent } from '你的分页组件路径'; @ViewChild('pagination') paginationComp!: ProductPaginationComponent; onCategoryChange(cat?: string): void { this.showAllProductsByCategory(1, cat); // 调用的是页面上真实渲染的分页组件的方法 this.paginationComp.initPagesNumbers(cat); }
可选解决方案2:共享服务通信(适合跨层级组件场景)
如果后续还有其他组件需要用到分类选中状态,可以用全局共享服务实现通信:
步骤1:创建共享状态服务
// category-state.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CategoryStateService { private selectedCategory$ = new BehaviorSubject<string|undefined>(undefined); currentCategory$ = this.selectedCategory$.asObservable(); updateCategory(cat?: string): void { this.selectedCategory$.next(cat); } }
步骤2:分类组件触发状态更新
// CategoryListComponent 逻辑代码 constructor(private categoryState: CategoryStateService) {} chooseCategory(cat?: string): void { this.categoryState.updateCategory(cat); }
步骤3:分页组件订阅状态变化
// ProductPaginationComponent 逻辑代码 constructor(private categoryState: CategoryStateService, private productService: ProductService) {} ngOnInit() : void { this.initPagesNumbers(); // 订阅分类变化自动更新分页 this.categoryState.currentCategory$.subscribe(cat => { this.initPagesNumbers(cat); }) } initPagesNumbers(category?:string) { this.productService.getCountOfProducts(category).subscribe(data =>{ const pagesCount = 10; // 直接赋值新数组比按索引赋值更易触发变更检测 this.pagesNumbers = Array.from({length: pagesCount}, (_, i) => i); }) }
为什么你之前的尝试都无效?
- 你注入的组件实例是未挂载的游离对象,修改它的属性和页面上的组件毫无关系,无论怎么调用变更检测方法都不会生效;
- 你之前定义的ReplaySubject是写在单个组件内部的,两个兄弟组件拿到的不是同一个Subject实例,自然无法传递消息,只有放到全局单例的共享服务中才能共享同一个实例。
内容的提问来源于stack exchange,提问作者Самый Важный
相关产品推荐
相关产品推荐

