如何用Angular本地数组替代API实现数据增删改查
解决方案
1. 改造CourseService,用BehaviorSubject管理课程数据
之前直接返回数组导致订阅报错,核心原因是subscribe仅支持Observable类型。用BehaviorSubject包装本地数据,既能提供可观察流,又能保存当前状态,操作数据后自动同步给所有订阅者。
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; // 定义课程数据结构 export interface Course { id: number; // 唯一ID,用于更新/删除定位 cName: string; bDesc: string; amt: number; dur: number; } @Injectable({ providedIn: 'root' }) export class CourseService { // 替换为你的原始courseList数组 private initialCourses: Course[] = [ { id: 1, cName: 'Angular核心教程', bDesc: '从入门到精通', amt: 199, dur: 40 }, { id: 2, cName: 'RxJS实战', bDesc: '响应式编程技巧', amt: 149, dur: 25 } ]; // 用BehaviorSubject存储数据,初始值为本地课程列表 private coursesSubject = new BehaviorSubject<Course[]>(this.initialCourses); // 对外暴露只读Observable,防止外部直接修改源数据 public courses$: Observable<Course[]> = this.coursesSubject.asObservable(); constructor() { } // 获取所有课程(返回Observable,支持组件订阅) getAllCourses(): Observable<Course[]> { return this.courses$; } // 新增课程 addCourse(course: Omit<Course, 'id'>): void { const currentList = this.coursesSubject.value; // 生成唯一ID(可根据实际需求调整规则) const newId = currentList.length ? Math.max(...currentList.map(c => c.id)) + 1 : 1; const newCourse = { ...course, id: newId }; // 推送新数组,触发所有订阅者更新 this.coursesSubject.next([...currentList, newCourse]); } // 更新课程 updateCourse(updatedCourse: Course): void { const currentList = this.coursesSubject.value; const updatedList = currentList.map(c => c.id === updatedCourse.id ? updatedCourse : c ); this.coursesSubject.next(updatedList); } // 删除课程 deleteCourse(courseId: number): void { const currentList = this.coursesSubject.value; const updatedList = currentList.filter(c => c.id !== courseId); this.coursesSubject.next(updatedList); } }
2. 组件改造:实现表单操作与数据订阅
组件类代码
import { Component, OnInit, OnDestroy } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { CourseService, Course } from './course.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-course-manager', templateUrl: './course-manager.component.html', styleUrls: ['./course-manager.component.css'] }) export class CourseManagerComponent implements OnInit, OnDestroy { courseForm: FormGroup; courses: Course[] = []; selectedCourse: Course | null = null; private courseSub: Subscription | null = null; constructor( private fb: FormBuilder, private courseService: CourseService ) { // 初始化响应式表单,添加字段校验 this.courseForm = this.fb.group({ cName: ['', Validators.required], bDesc: ['', Validators.required], amt: [0, [Validators.required, Validators.min(0)]], dur: [0, [Validators.required, Validators.min(1)]] }); } ngOnInit(): void { // 订阅课程数据,实时同步表格展示 this.courseSub = this.courseService.getAllCourses().subscribe(courses => { this.courses = courses; }); } ngOnDestroy(): void { // 取消订阅,避免内存泄漏 this.courseSub?.unsubscribe(); } // 单选按钮选中课程,填充表单 onCourseSelect(course: Course): void { this.selectedCourse = course; this.courseForm.patchValue(course); } // 提交表单:区分新增/更新逻辑 onSubmit(): void { if (this.courseForm.invalid) return; const formData = this.courseForm.value; if (this.selectedCourse) { // 更新课程:合并选中课程的ID与表单数据 const updatedCourse = { ...this.selectedCourse, ...formData }; this.courseService.updateCourse(updatedCourse); } else { // 新增课程 this.courseService.addCourse(formData); } this.resetForm(); } // 删除选中课程 deleteSelected(): void { if (!this.selectedCourse) return; this.courseService.deleteCourse(this.selectedCourse.id); this.resetForm(); } // 重置表单与选中状态 resetForm(): void { this.courseForm.reset({ amt: 0, dur: 0 }); this.selectedCourse = null; } }
组件模板代码
<!-- 课程操作表单 --> <form [formGroup]="courseForm" (ngSubmit)="onSubmit()"> <div class="form-group"> <label>课程名称:</label> <input formControlName="cName" type="text"> <span *ngIf="courseForm.get('cName')?.invalid && courseForm.get('cName')?.touched"> 课程名称不能为空 </span> </div> <div class="form-group"> <label>课程简介:</label> <textarea formControlName="bDesc"></textarea> <span *ngIf="courseForm.get('bDesc')?.invalid && courseForm.get('bDesc')?.touched"> 课程简介不能为空 </span> </div> <div class="form-group"> <label>金额:</label> <input formControlName="amt" type="number"> <span *ngIf="courseForm.get('amt')?.invalid && courseForm.get('amt')?.touched"> 金额必须大于等于0 </span> </div> <div class="form-group"> <label>时长:</label> <input formControlName="dur" type="number"> <span *ngIf="courseForm.get('dur')?.invalid && courseForm.get('dur')?.touched"> 时长必须大于等于1 </span> </div> <button type="submit" [disabled]="courseForm.invalid"> {{ selectedCourse ? '更新课程' : '新增课程' }} </button> <button type="button" (click)="resetForm()">重置</button> <button type="button" (click)="deleteSelected()" [disabled]="!selectedCourse"> 删除选中课程 </button> </form> <!-- 课程列表表格 --> <table> <thead> <tr> <th>选择</th> <th>课程名称</th> <th>简介</th> <th>金额</th> <th>时长</th> </tr> </thead> <tbody> <tr *ngFor="let course of courses"> <td> <input type="radio" name="courseSelect" (change)="onCourseSelect(course)" [checked]="selectedCourse?.id === course.id"> </td> <td>{{ course.cName }}</td> <td>{{ course.bDesc }}</td> <td>{{ course.amt }}</td> <td>{{ course.dur }}</td> </tr> </tbody> </table>
关键说明
- 所有数据操作(增删改)都会通过CourseService更新BehaviorSubject的值,组件订阅的
courses$会自动收到最新数据,实现表格实时刷新。 - 表单通过
selectedCourse的存在状态区分新增/更新逻辑,选中课程后自动填充表单字段。 - 组件销毁时必须取消订阅,避免内存泄漏。
内容的提问来源于stack exchange,提问作者AnkaDel
相关产品推荐
相关产品推荐

