You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 02:52:10