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

Angular批量更新多记录及Impact分类数量统计需求实现

Angular HttpClient批量更新与Impact统计实现方案

我帮你梳理并修正了代码,解决了批量更新和Impact分类统计的核心需求,以下是完整的实现方案,包含关键逻辑的优化和BUG修复:

1. 服务层(common.service.ts)

原服务层代码基础上新增了批量更新辅助方法,利用forkJoin并行处理多个更新请求,提升操作效率:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class CommonService {
  constructor(private http: HttpClient) { }
  
  createUser(user: any) {
    return this.http.post("http://localhost:3000/users", user);
  }
  
  getAllUser() {
    return this.http.get("http://localhost:3000/users");
  }
  
  updateUser(user: any): Observable<any> {
    return this.http.put(`http://localhost:3000/users/${user.id}`, user);
  }
  
  deleteUser(user: any) {
    return this.http.delete(`http://localhost:3000/users/${user.id}`);
  }

  // 新增批量更新辅助方法,并行处理多个更新请求
  batchUpdateUsers(users: any[]): Observable<any[]> {
    const updateRequests = users.map(user => this.updateUser(user));
    return forkJoin(updateRequests);
  }
}

2. 组件逻辑层(app.component.ts)

修正了原代码中的全选逻辑错误、批量更新重复API调用、复选框状态同步等问题,优化了统计逻辑:

import { Component } from '@angular/core';
import { CommonService } from './common.service';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'db-poc1';
  allUser: any[] = [];
  isEdit = false;
  isView = false;
  isBatchEdit = false;
  totalRecords: number = 0;
  page: number = 1;
  currentImpact: string = '';
  selectAll: boolean = false; // 统一管理全选状态
  impactCount = { applicable: 0, notapplicable: 0, fyi: 0 };
  batchUpdateUsers: any[] = [];

  userObj = {
    id: '',
    first_name: '',
    last_name: '',
    email: '',
    gender: '',
    ip_address: '',
    impact: ''
  };

  constructor(private commonService: CommonService) {}

  ngOnInit() {
    this.getLatestUser();
  }

  // 单条复选框点击事件,同步批量选中列表
  checkboxClicked() {
    this.batchUpdateUsers = this.allUser.filter(row => row.checked);
    this.isBatchEdit = this.batchUpdateUsers.length > 0;
    this.isView = false;
  }

  // 全选/反选事件,同步所有行的复选框状态
  selectAllClicked() {
    this.allUser.forEach(item => item.checked = this.selectAll);
    this.checkboxClicked();
  }

  addUser(formObj: any) {
    this.commonService.createUser(formObj).subscribe(() => {
      this.getLatestUser();
    });
  }

  // 获取最新用户列表并初始化状态
  getLatestUser() {
    this.commonService.getAllUser().subscribe((response: any[]) => {
      this.allUser = response.map(user => ({ ...user, checked: false }));
      this.totalRecords = this.allUser.length;
      this.calculateImpactCounts();
    });
  }

  // 计算Impact分类统计数量
  calculateImpactCounts() {
    this.impactCount = { applicable: 0, notapplicable: 0, fyi: 0 };
    this.allUser.forEach(row => {
      switch(row.impact) {
        case 'Applicable':
          this.impactCount.applicable++;
          break;
        case 'Not Applicable':
          this.impactCount.notapplicable++;
          break;
        case 'FYI':
          this.impactCount.fyi++;
          break;
      }
    });
  }

  editUser(user: any) {
    this.isEdit = true;
    this.userObj = { ...user };
    this.allUser.forEach(u => u.checked = false);
    this.currentImpact = user.impact;
  }

  deleteUser(user: any) {
    this.commonService.deleteUser(user).subscribe(() => {
      this.getLatestUser();
    });
  }

  updateUser() {
    this.isEdit = false;
    this.userObj.impact = this.currentImpact;
    this.commonService.updateUser(this.userObj).subscribe(() => {
      this.getLatestUser();
    });
  }

  cancelEdit() {
    this.isEdit = false;
    this.isView = false;
  }

  viewUser(user: any) {
    this.isView = true;
    this.userObj = { ...user };
  }

  // 取消批量编辑,重置状态
  cancelBatchEdit() {
    this.isBatchEdit = false;
    this.selectAll = false;
    this.allUser.forEach(user => user.checked = false);
    this.currentImpact = '';
  }

  // 批量更新核心逻辑
  batchUpdateUser() {
    if (!this.currentImpact || this.batchUpdateUsers.length === 0) return;

    const updatedUsers = this.batchUpdateUsers.map(user => ({
      ...user,
      impact: this.currentImpact
    }));

    this.commonService.batchUpdateUsers(updatedUsers).subscribe(() => {
      this.getLatestUser();
      this.cancelBatchEdit();
    });
  }
}

3. 模板层(app.component.html)

修正了复选框绑定冲突、全选状态同步问题,增强了统计信息的直观性:

<div class="container-fluid">
  <div class="text-right toal-records">Total: {{totalRecords}}</div>
  
  <!-- Impact统计图表(显示具体数量) -->
  <div class="skills">
    <ul class="labels">
      <li>Applicable ({{impactCount.applicable}})</li>
      <li>Not Applicable ({{impactCount.notapplicable}})</li>
      <li>FYI ({{impactCount.fyi}})</li>
    </ul>
    <ul class="lines">
      <li class="line l--0"><span class="line__label">0</span></li>
      <li class="line l--1"><span class="line__label">1</span></li>
      <li class="line l--2"><span class="line__label">2</span></li>
      <li class="line l--3"><span class="line__label">3</span></li>
      <li class="line l--4"><span class="line__label">4</span></li>
      <li class="line l--5"><span class="line__label">5</span></li>
      <li class="line l--6"><span class="line__label">6</span></li>
      <li class="line l--7"><span class="line__label">7</span></li>
      <li class="line l--8"><span class="line__label">8</span></li>
      <li class="line l--9"><span class="line__label">9</span></li>
    </ul>
    <div class="charts">
      <div class="chart chart--dev">
        <ul class="chart--horiz">
          <li class="chart__bar" [style.width]="impactCount.applicable * 10 + '%'"></li>
          <li class="chart__bar" [style.width]="impactCount.notapplicable * 10 + '%'"></li>
          <li class="chart__bar" [style.width]="impactCount.fyi * 10 + '%'"></li>
        </ul>
      </div>
    </div>
  </div>

  <!-- 用户列表 -->
  <table class="table table-sm table-responsive">
    <thead>
      <tr>
        <th>
          <input type="checkbox" [(ngModel)]="selectAll" (change)="selectAllClicked()">
        </th>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Email</th>
        <th>Gender</th>
        <th>IP Address</th>
        <th>Impact</th>
      </tr>
    </thead>
    <tbody>
      <tr class="record-row" (click)="viewUser(user)" *ngFor="let user of allUser | paginate: { id: 'listing_pagination', itemsPerPage: 10, currentPage: page, totalItems: totalRecords }">
        <td>
          <input *ngIf="!isEdit" type="checkbox" [(ngModel)]="user.checked" (change)="checkboxClicked()">
        </td>
        <td>{{user.first_name}}</td>
        <td>{{user.last_name}}</td>
        <td>{{user.email}}</td>
        <td>{{user.gender}}</td>
        <td>{{user.ip_address}}</td>
        <td>{{user.impact}}</td>
      </tr>
    </tbody>
  </table>

  <pagination-controls id="listing_pagination" directionLinks="true" (pageChange)="page = $event"></pagination-controls>

  <!-- 查看详情 -->
  <div *ngIf="isView" class="view-details">
    <ul>
      <li>First Name <br />{{userObj.first_name}}</li>
      <li>Last Name <br />{{userObj.last_name}}</li>
      <li>Email <br />{{userObj.email}}</li>
      <li>Gender <br />{{userObj.gender}}</li>
      <li>IP Address <br />{{userObj.ip_address}}</li>
      <li>Impact <br />{{userObj.impact}}</li>
    </ul>
  </div>

  <!-- 批量更新表单(添加非空校验) -->
  <form #myForm="ngForm">
    <div class="form-group">
      <select name="impact" [disabled]="!isBatchEdit" class="form-control form-control-sm" [(ngModel)]="currentImpact">
        <option value="" disabled selected>Change Impact</option>
        <option>Applicable</option>
        <option>Not Applicable</option>
        <option>FYI</option>
      </select>
    </div>
    <button type="button" [disabled]="!isBatchEdit || !currentImpact" (click)="batchUpdateUser(); myForm.reset()" class="btn btn-success btn-sm btn-update mr-2">
      Update 
    </button>
    <button type="button" [disabled]="!isBatchEdit" (click)="cancelBatchEdit(); myForm.reset()" class="btn btn-secondary btn-sm">Cancel</button>
  </form>
</div>

4. 数据文件(db.json)

保持原数据结构不变:

{
  "users": [
    {
      "id": 1,
      "first_name": "Kunal",
      "last_name": "Vijan",
      "email": "vijan87@gmail.com",
      "gender": "Male",
      "ip_address": "1.1.1.1",
      "impact": "Applicable"
    },
    {
      "id": 2,
      "first_name": "Kunal",
      "last_name": "Vijan",
      "email": "vijan87@gmail.com",
      "gender": "Male",
      "ip_address": "1.1.1.1",
      "impact": "Not Applicable"
    },
    {
      "id": 3,
      "first_name": "Kunal",
      "last_name": "Vijan",
      "email": "vijan87@gmail.com",
      "gender": "Male",
      "ip_address": "1.1.1.1",
      "impact": "FYI"
    }
  ]
}

关键修改说明

  1. 全选/反选逻辑:统一使用selectAll变量绑定全选复选框,点击时同步所有行的checked状态,避免状态不一致
  2. 批量更新优化:使用forkJoin并行处理多个更新请求,提升性能,同时避免原代码中的重复API调用
  3. 统计功能增强:在统计标签上直接显示数量,让数据更直观,同时确保每次数据刷新后自动重新统计
  4. UI交互优化:添加了currentImpact的非空校验,避免无意义的批量更新操作;修正了复选框的绑定冲突问题
  5. 状态重置:批量更新或取消编辑时,统一重置相关状态变量,确保界面状态正确

内容的提问来源于stack exchange,提问作者Kunal Vijan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:08:10