Angular8 FormArray中起止时间下拉选项联动更新需求
Hey,我来帮你搞定这个Angular 8表单里的时间联动需求!针对你说的FormArray中每行开始/结束时间的互斥,还有新增行的时间限制,我整理了一套完整的实现方案,咱们一步步来拆解:
实现思路与代码示例
1. 先准备基础时间选项数据
首先得定义好所有可选的时间列表,用键值对形式存储,方便后续做时间大小的比较和显示:
// 组件内定义基础时间选项 timeOptions = [ { value: '09:00', label: '9AM' }, { value: '10:00', label: '10AM' }, { value: '11:00', label: '11AM' }, { value: '12:00', label: '12PM' }, { value: '13:00', label: '1PM' }, { value: '14:00', label: '2PM' }, { value: '15:00', label: '3PM' }, { value: '16:00', label: '4PM' }, { value: '17:00', label: '5PM' }, { value: '18:00', label: '6PM' }, { value: '19:00', label: '7PM' }, { value: '20:00', label: '8PM' } ];
2. 初始化FormGroup与FormArray
创建包含时间数组的表单结构,同时封装一个创建单行时间控件的方法:
import { FormGroup, FormArray, FormControl } from '@angular/forms'; // 组件内初始化表单 form = new FormGroup({ timings: new FormArray([this.createTimingGroup()]) }); // 获取FormArray的快捷方式 get timings() { return this.form.get('timings') as FormArray; } // 创建单行时间控件组 createTimingGroup() { const timingGroup = new FormGroup({ skill: new FormControl(''), // 对应开始时间控件 exp: new FormControl('') // 对应结束时间控件 }); // 可选优化:监听当前行结束时间变化,清空下一行的时间(避免冲突) timingGroup.get('exp')?.valueChanges.subscribe(() => { const currentIndex = this.timings.controls.indexOf(timingGroup); if (currentIndex < this.timings.length - 1) { const nextGroup = this.timings.at(currentIndex + 1) as FormGroup; nextGroup.patchValue({ skill: '', exp: '' }); } }); return timingGroup; }
3. 实现单内行的开始→结束时间联动
写一个方法,根据当前行选择的开始时间,过滤出仅晚于它的结束时间选项:
// 获取当前行可用的结束时间选项 getEndTimeOptions(index: number) { const currentGroup = this.timings.at(index) as FormGroup; const selectedStartTime = currentGroup.get('skill')?.value; if (!selectedStartTime) return this.timeOptions; // 利用时间字符串的字典序比较,过滤出晚于开始时间的选项 return this.timeOptions.filter(option => option.value > selectedStartTime); }
4. 实现新增行的开始时间限制
再写一个方法,根据当前行的索引,判断是否需要依赖上一行的结束时间来过滤开始时间选项:
// 获取当前行可用的开始时间选项 getStartTimeOptions(index: number) { // 第一行显示全部时间选项 if (index === 0) return this.timeOptions; const prevGroup = this.timings.at(index - 1) as FormGroup; const prevEndTime = prevGroup.get('exp')?.value; if (!prevEndTime) return this.timeOptions; // 仅显示晚于上一行结束时间的选项 return this.timeOptions.filter(option => option.value > prevEndTime); } // 新增时间行的方法 addTiming() { this.timings.push(this.createTimingGroup()); }
5. 模板层绑定逻辑
最后在HTML模板中,把这些方法和表单控件绑定起来:
<form [formGroup]="form"> <div formArrayName="timings"> <!-- 遍历每一行时间控件 --> <div *ngFor="let timing of timings.controls; let i = index" [formGroup]="timing"> <!-- 开始时间下拉框 --> <select formControlName="skill"> <option value="">Select start time</option> <option *ngFor="let time of getStartTimeOptions(i)" [value]="time.value"> {{time.label}} </option> </select> <!-- 结束时间下拉框 --> <select formControlName="exp"> <option value="">Select end time</option> <option *ngFor="let time of getEndTimeOptions(i)" [value]="time.value"> {{time.label}} </option> </select> </div> </div> <!-- 新增时间行按钮 --> <button type="button" (click)="addTiming()">add timing</button> </form>
这样就完全实现了你需要的两个核心需求:
- 选择某一行开始时间后,该行结束时间仅展示晚于它的选项
- 新增行的开始时间,仅展示晚于上一行结束时间的选项,且新行的开始/结束时间同样遵循联动规则
内容的提问来源于stack exchange,提问作者rawrstar
相关产品推荐
相关产品推荐

