Angular点击添加按钮动态生成空问题组件的实现方法
嘿,这个需求在Angular项目里太常见了,我来给你一步步拆解实现思路:
1. 先定义问题的数据模型
首先你需要一个统一的模型来描述每个问题的字段,这样父组件和子组件之间的数据传递才会清晰。创建一个Question接口(或者类):
// src/app/models/question.model.ts export interface Question { id: string; title: string; // 问题标题 type: 'text' | 'radio' | 'checkbox'; // 支持的问题类型,可按需扩展 options: string[]; // 单选/多选的选项列表 }
2. 在父组件(问卷配置页)维护问题数组
父组件负责管理所有问题的集合,点击「添加问题」按钮时,向数组中推入一个空的问题对象:
// src/app/components/survey-config/survey-config.component.ts import { Component } from '@angular/core'; import { Question } from '../../models/question.model'; @Component({ selector: 'app-survey-config', templateUrl: './survey-config.component.html', styleUrls: ['./survey-config.component.css'] }) export class SurveyConfigComponent { // 存储所有问题的数组,初始为空 questions: Question[] = []; // 生成唯一ID,避免问题重复 private generateUniqueId(): string { return `question-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; } // 添加新问题的方法 addQuestion(): void { const newEmptyQuestion: Question = { id: this.generateUniqueId(), title: '', type: 'text', // 默认文本类型 options: [] }; this.questions.push(newEmptyQuestion); } // 可选:删除问题的方法(如果需要) deleteQuestion(index: number): void { this.questions.splice(index, 1); } }
3. 父组件模板循环渲染问题组件
用*ngFor遍历问题数组,把每个问题对象通过@Input传给你的问题子组件,同时添加「添加问题」按钮:
<!-- src/app/components/survey-config/survey-config.component.html --> <div class="survey-config-container"> <button class="add-question-btn" (click)="addQuestion()" > 添加问题 </button> <!-- 假设你的问题组件选择器是app-question-item --> <app-question-item *ngFor="let question of questions; let i = index" [question]="question" (onDelete)="deleteQuestion(i)" ></app-question-item> </div>
4. 实现问题子组件
子组件接收父组件传入的question对象,用双向绑定([(ngModel)])绑定各个字段,这样用户输入的内容会实时同步到父组件的数组里:
// src/app/components/question-item/question-item.component.ts import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Question } from '../../models/question.model'; @Component({ selector: 'app-question-item', templateUrl: './question-item.component.html', styleUrls: ['./question-item.component.css'] }) export class QuestionItemComponent { @Input() question!: Question; // 接收父组件传入的问题数据 @Output() onDelete = new EventEmitter<void>(); // 通知父组件删除当前问题 // 给单选/多选添加空选项 addOption(): void { this.question.options.push(''); } // 删除单个选项 removeOption(index: number): void { this.question.options.splice(index, 1); } }
子组件的模板示例(根据问题类型动态显示不同字段):
<!-- src/app/components/question-item/question-item.component.html --> <div class="question-card"> <!-- 问题标题输入框 --> <input type="text" placeholder="请输入问题标题" [(ngModel)]="question.title" class="question-title-input" > <!-- 问题类型选择 --> <select [(ngModel)]="question.type" class="question-type-select"> <option value="text">文本输入</option> <option value="radio">单选</option> <option value="checkbox">多选</option> </select> <!-- 单选/多选的选项区域 --> <div *ngIf="question.type !== 'text'" class="options-section"> <div *ngFor="let option of question.options; let j = index" class="option-item"> <input type="text" placeholder="请输入选项内容" [(ngModel)]="question.options[j]" > <button (click)="removeOption(j)">删除选项</button> </div> <button (click)="addOption()" class="add-option-btn">添加选项</button> </div> <!-- 删除当前问题按钮 --> <button (click)="onDelete.emit()" class="delete-question-btn">删除问题</button> </div>
5. 别忘了导入FormsModule
因为用到了[(ngModel)]双向绑定,必须在你的模块(比如AppModule)里导入FormsModule:
// src/app/app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; // 导入这个 import { AppComponent } from './app.component'; import { SurveyConfigComponent } from './components/survey-config/survey-config.component'; import { QuestionItemComponent } from './components/question-item/question-item.component'; @NgModule({ declarations: [ AppComponent, SurveyConfigComponent, QuestionItemComponent ], imports: [ BrowserModule, FormsModule // 添加到imports数组 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
额外提示
- 如果你的问卷需要更复杂的表单验证,建议用
FormArray来管理问题集合,结合FormGroup和Validators,这是Angular表单的最佳实践 - 生成唯一ID的方法可以换成更可靠的库(比如
uuid),不过上面的简易方法足够应付大部分场景 - 可以给问题组件添加动画效果,比如新增时的淡入,提升用户体验
内容的提问来源于stack exchange,提问作者Stefan_Griffiths
相关产品推荐
相关产品推荐

