Angular:修改克隆DOM元素的ng-model值,解决克隆元素同步问题
解决Angular克隆模板后共享ng-model的问题
你碰到的问题很典型:所有通过ng-template克隆出来的元素都绑定到组件类里同一个questiontype变量,所以任何一个下拉菜单的选择都会同步到所有克隆实例上。要解决这个问题,核心思路是给每个克隆项分配独立的状态数据,让它们绑定到各自的变量,而不是共享组件级的全局变量。
下面是具体的修改步骤:
1. 修改TypeScript代码
首先,我们需要存储每个克隆项的独立状态,并且在创建视图时传递专属的上下文:
import { Component, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core'; @Component({ // ...你的组件元数据 }) export class YourComponent { @ViewChild('clone') template: TemplateRef<any>; @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef; // 存储每个克隆项的独立状态,初始包含一个默认项(对应首次显示的内容) private clonedQuestionItems: Array<{ questiontype: string }> = [{ questiontype: 'multiplechoice' }]; ngAfterViewInit() { // 初始化时渲染第一个默认项 this.renderItems(); } cloneTemplate() { // 添加新的克隆项,默认类型为multiplechoice this.clonedQuestionItems.push({ questiontype: 'multiplechoice' }); // 重新渲染所有项(确保视图和数据同步) this.renderItems(); } changeOptions(item: { questiontype: string }, newType: string) { // 修改当前项的类型,而非全局变量 item.questiontype = newType; } private renderItems() { // 清空容器后重新渲染所有项 this.container.clear(); this.clonedQuestionItems.forEach(item => { const view = this.template.createEmbeddedView({ $implicit: item }); this.container.insert(view); }); } }
2. 修改HTML模板
接下来,让模板接收每个项的上下文数据,绑定到各自的questiontype属性:
<!-- 承载克隆视图的容器 --> <div #container></div> <ng-template #clone let-item> <div class="mask1" *ngIf="question1 === true"> <div class=""> <div style="margin-left:15px"> <div class="row margin-top-10"> <div class="col-lg-1 col-sm-1 col-md-1 col-xs-1 "> <button mat-mini-fab class="oval"> <!-- 显示项的序号,基于数组索引 --> {{ clonedQuestionItems.indexOf(item) + 1 }} </button> </div> <div class="col-lg-5 col-sm-5 col-md-5 col-xs-5 how-do-you-feel margin-top-10 "> How do you feel? <div class="line"></div> </div> <div class="col-lg-6 col-sm-6 col-md-6 col-xs-6 "> <div class="col-xs-11"> <!-- 判断当前项的类型,而非全局变量 --> <mat-radio-button class="pull-right" value="1" *ngIf="item.questiontype === 'multiplechoice'"> </mat-radio-button> <mat-form-field class="choices"> <!-- 绑定到当前项的questiontype属性 --> <mat-select [(ngModel)]="item.questiontype" (selectionChange)="changeOptions(item, $event.value)" class="choices"> <mat-option value="paragraph"> <span class="glyphicon glyphicon-align-justify choices "></span> Paragraph </mat-option> <mat-option value="multiplechoice"> <span class="glyphicon glyphicon-record choices"></span> Multiple choice </mat-option> <mat-option value="checkboxes"> <span class="glyphicon glyphicon-check choices"></span> Checkboxes </mat-option> <mat-option value="linearscale"> <span class="glyphicon glyphicon-option-horizontal choices"></span> Linear scale </mat-option> <mat-option value="date"> <span class="glyphicon glyphicon-calendar choices"></span> Date </mat-option> </mat-select> </mat-form-field> <!-- 修复复制按钮的标签,改为正确的img标签 --> <img src="assets/img/dublicate@3x.png" class="dublicate" (click)="cloneTemplate()" /> </div> </div> </div> </div> </div> </div> </ng-template>
关键改动说明
- 独立状态存储:用
clonedQuestionItems数组保存每个克隆项的questiontype,每个项都有自己的状态副本,互不干扰。 - 上下文传递:通过
createEmbeddedView({ $implicit: item })把每个项的数据传递给模板,模板用let-item接收这个专属上下文。 - 绑定到项的属性:所有依赖
questiontype的地方(比如ngModel、*ngIf)都改成绑定到item.questiontype,而非组件的全局变量。
这样修改后,每个克隆的下拉菜单选择只会影响自己对应的项,不会再出现所有元素同步变化的问题。如果之后需要收集所有项的状态,直接遍历clonedQuestionItems数组即可。
内容的提问来源于stack exchange,提问作者Raj Rana
相关产品推荐
相关产品推荐

