Angular6内容投影中结构指令失效,如何正确使用*ngIf与*ngFor?
解决Angular内容投影中结构指令(*ngFor/*ngIf)不生效的问题
哈哈,这个坑我刚踩过不久!你遇到的问题核心在于内容投影的上下文作用域和结构指令的执行时机,我来给你拆解清楚并解决:
问题根源
你现在直接把带*ngFor/*ngIf的表格放在<common-modal>标签里,这些结构指令是在父组件的模板上下文中执行的——也就是说,你写的*ngFor='let d of serverData'其实是在遍历父组件的serverData,而不是子组件@Input接收的那个serverData。更关键的是,如果模态框是延迟渲染(比如点击按钮才显示),父组件的变更检测可能不会同步触发投影内容的更新,导致指令看起来“没生效”。
正确解决方案:带上下文的内容投影
要让投影内容能使用子组件的上下文变量(比如子组件接收的data),我们需要用ng-template包裹投影内容,配合子组件的ngTemplateOutlet来传递上下文。具体步骤如下:
1. 修改父组件的模板
把原来的表格内容包裹在<ng-template>里,通过let-xxx="yyy"的语法声明要接收子组件传递的上下文变量:
<common-modal [data]="serverData"> <!-- 用ng-template包裹投影内容,let-data接收子组件传来的modalData --> <ng-template let-data="modalData"> <table class="table"> <thead> <tr> <th scope="col">IP Address</th> <th scope="col">Count</th> <th scope="col">Keyword</th> </tr> </thead> <tbody> <tr *ngFor='let d of data'> <td>{{d.ip}}</td> <td>{{d.count}}</td> <td>{{d.keyword}}</td> </tr> </tbody> <tbody *ngIf='data?.length==0'> <tr> <td colspan='3'> no data to display </td> </tr> </tbody> </table> </ng-template> </common-modal>
2. 修改子组件的TS代码
通过@ContentChild(TemplateRef)获取父组件传递的模板,并保留@Input接收数据:
import { Component, OnInit, Input, ContentChild, TemplateRef } from '@angular/core'; @Component({ selector: 'common-modal', templateUrl: './common-modal.component.html', styleUrls: ['./common-modal.component.css'] }) export class CommonModalComponent implements OnInit { @Input() data: any[] = []; // 获取父组件传递的ng-template模板 @ContentChild(TemplateRef) modalContent!: TemplateRef<any>; constructor() { } ngOnInit() { } }
3. 修改子组件的HTML模板
在模态框的主体部分,用ngTemplateOutlet渲染获取到的模板,并通过context参数把子组件的data传递给模板:
<!-- 这里以Bootstrap模态框为例,你可以替换成自己的模态框结构 --> <div class="modal" tabindex="-1" role="dialog" [class.show]="isOpen"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Server Data</h5> <button type="button" class="close" (click)="closeModal()"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <!-- 渲染投影模板,并传递上下文:把data命名为modalData --> <ng-container *ngTemplateOutlet="modalContent; context: { modalData: data }" ></ng-container> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" (click)="closeModal()">Close</button> </div> </div> </div> </div>
为什么这样有效?
ng-template把投影内容变成了一个可复用的模板片段,不会在父组件中直接渲染,而是由子组件控制渲染时机。ngTemplateOutlet在子组件的上下文中渲染模板,通过context传递的变量会被模板接收,这样*ngFor/*ngIf就会基于子组件的data执行,当data变化时,子组件的变更检测会自动触发模板更新。- 彻底解决了父/子组件上下文混淆的问题,确保结构指令使用的是正确的数据。
内容的提问来源于stack exchange,提问作者Lijin Durairaj
相关产品推荐
相关产品推荐

