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

Angular中ngFor遍历数组仅显示最后一项问题求助

问题描述

我通过Service将create组件的输入数据传递至check组件,在check组件中把这些数据存储在receipts数组内。当在check页面的表格中使用ngFor遍历该数组时,仅显示数组的最后一项,但控制台打印数组时所有数据均存在,请问问题出在哪里?能否给出解决建议?


相关代码

Check 组件 TS 文件

ngOnInit(): void {
    console.log("check oninit");

    this.subscription();
}

receipts: any[] = [];

subscription() {
    this.receiptdataService.behaveiorSubject$.subscribe((res: any)=>{
        for (const [key, val] of Object.entries(res)) {
            console.log(`${key}: ${val} + 2. respo`);
        }
        this.receipts.push(res)
        console.log(this.receipts)
    })
} 

Check 组件 HTML 文件

<h2 class="display-6">Kiállított számlák:</h2>
<table class="table">
    <tr>
        <th>ID</th>
        <th>Vásárló neve</th>
        <th>Kiállítás dátuma</th>
        <th>Esedékesség dátuma</th>
        <th>Tétel neve</th>
        <th>Komment</th>
        <th>Ár</th>
   <tr>
    <tr *ngFor="let item of receipts" >
        <td>{{item.name}}</td>
        <td >{{item.date}}</td>
        <td >{{item.date2}}</td>
        <td >{{item.item}}</td>
        <td >{{item.comment}}</td>
        <td >{{item.price}}</td>
    </tr>
  
</table>

服务代码

private sourceBehav = new BehaviorSubject<any>(null);
public behaveiorSubject$ = this.sourceBehav.asObservable();

showReceipt(value: any) {
    this.sourceBehav.next(value)
}

Create 组件 TS 文件(数据发出处)

sendData(value: any): void {
    // for (const [key, val] of Object.entries(value)) {
    //   console.log(`${key}: ${val}`);
    // }
    this.receiptdataService.showReceipt(value);
}

Create 组件 HTML 文件

<div>
  <h2 class="display-6">Állítson elő számlát:</h2>
  <form [formGroup]="receiptform" #save="ngForm" (ngSubmit)="onSubmit(save.value)" action="POST">
    <ul>
      <li>
        <label for="cusName" class="form-label">Vásárló neve</label>
        <input formControlName="name" type="text" class="form-control" id="cusName" #nameval>
      </li>
      <span *ngIf=" name!.invalid && (name!.dirty || name!.touched)">
        <span [ngStyle]="{'color':'red'}" *ngIf="name!.errors?.['required']">
          A név kötelező!
        </span>
        <span [ngStyle]="{'color':'red'}" *ngIf="name!.errors?.['pattern']">
          Hibás formmátum!
        </span>
      </span>
      <li>
        <label for="date" class="form-label">Kiállítás dátuma</label>
        <input formControlName="date" [max]="maxDate" type="date" class="form-control" id="date">
      </li>
      <span *ngIf=" date!.invalid && (date!.dirty || date!.touched)">
        <span [ngStyle]="{'color':'red'}" *ngIf="date!.errors?.['required']">
          A dátum kötelező!
        </span>
      </span>
      <li>
        <label for="date" class="form-label">Esedékesség dátuma</label>
        <input formControlName="date2" type="date" class="form-control" id="date">
      </li>
      <span *ngIf=" date2!.invalid && (date2!.dirty || date2!.touched)">
        <span [ngStyle]="{'color':'red'}" *ngIf="date2!.errors?.['required']">
          A dátum kötelező!
        </span>
      </span>
      <li>
        <label for="item" class="form-label">Tétel neve</label>
        <input formControlName="item" type="text" class="form-control" id="item">
      </li>
      <span *ngIf=" item!.invalid && (item!.dirty || item!.touched)">
        <span [ngStyle]="{'color':'red'}" *ngIf="item!.errors?.['required']">
          A tétel kötelező!
        </span>
      </span>
      <li>
        <label for="comment">Komment</label>
        <textarea formControlName="comment" class="form-control" id="comment"></textarea>
      </li>
      <span *ngIf=" comment!.invalid && (comment!.dirty || comment!.touched)">
        <span [ngStyle]="{'color':'red'}" *ngIf="comment!.errors?.['required']">
          Kötelező kommentelni!
        </span>
      </span>
      <li>
        <label for="price">Ár</label>
        <span style="width:30%" class="input-group mb-3">
          <input formControlName="price" type="number" min=1 class="form-control" id="price">
          <span class="input-group-text">,-Ft</span>
        </span>
      </li>
      <span *ngIf=" price!.invalid && (price!.dirty || price!.touched)">
        <span [ngStyle]="{'color':'red'}" *ngIf="price!.errors?.['required']">
          Az árkötelező!
        </span>

      </span>
      <button (click)="sendData(save.value)" [disabled]="!receiptform.valid" type="submit"
        class=" btn btn-outline-success">Mentés</button>
      <button routerLink="../subscription" class="mx-3 btn btn-outline-secondary">Visszalépés</button>

    </ul>
  </form>
</div>

问题原因与解决建议

问题原因

  1. 表格结构语法错误:Check组件HTML中,表头的<tr>标签未正确闭合(最后一行写成了<tr>而非</tr>),导致浏览器渲染时表格结构混乱,后续行元素被错误嵌套,最终仅显示最后一条数据。
  2. 变更检测未触发:数组是引用类型,push操作不会改变数组的引用地址,若组件使用OnPush变更检测策略,Angular可能无法感知数组变化,导致视图未更新。

解决建议

1. 修复模板结构

将Check组件HTML中表头的<tr>标签正确闭合:

<tr>
    <th>ID</th>
    <th>Vásárló neve</th>
    <th>Kiállítás dátuma</th>
    <th>Esedékesség dátuma</th>
    <th>Tétel neve</th>
    <th>Komment</th>
    <th>Ár</th>
</tr> <!-- 替换原错误的<tr>标签 -->

2. 确保变更检测触发

若修复模板后仍存在问题,可通过以下方式触发变更检测:

  • 创建新数组引用:替换push操作,生成新数组以触发Angular变更检测:
    this.receipts = [...this.receipts, res];
    
  • 手动触发变更检测:注入ChangeDetectorRef并调用detectChanges():
    import { ChangeDetectorRef } from '@angular/core';
    
    constructor(private cdr: ChangeDetectorRef) {}
    
    subscription() {
        this.receiptdataService.behaveiorSubject$.subscribe((res: any)=>{
            this.receipts.push(res);
            this.cdr.detectChanges(); // 手动触发视图更新
            console.log(this.receipts);
        });
    }
    

3. 额外优化建议

  • 定义类型接口:避免使用any类型,定义收据数据接口提升代码可维护性:
    interface Receipt {
        name: string;
        date: string;
        date2: string;
        item: string;
        comment: string;
        price: number;
    }
    
    receipts: Receipt[] = [];
    
  • 取消订阅防止内存泄漏:组件销毁时取消BehaviorSubject的订阅:
    import { Subscription } from 'rxjs';
    
    private subscription!: Subscription;
    
    subscription() {
        this.subscription = this.receiptdataService.behaveiorSubject$.subscribe((res: Receipt)=>{
            this.receipts = [...this.receipts, res];
        });
    }
    
    ngOnDestroy(): void {
        this.subscription.unsubscribe();
    }
    

内容的提问来源于stack exchange,提问作者Rebeka Süveges

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:45:54