在Angular中,如果这两个数据都绑定到对象,我该如何放弃编辑并恢复列表+列表项组件中的旧对象?

时间:2019-02-26 14:06:57

标签: angular

我正在尝试基于Angular“英雄”教程(如此之多!),在这里我对对象列表https://angular.io/tutorial/toh-pt3进行简单的CRUD操作,并且对象编辑组件出现在同一页面上作为对象列表组件,并且对象服务执行REST调用以启用所有功能。

<h2>Groups</h2>
<ul class="groups">
  <li *ngFor="let group of groups"
    [class.selected]="group === selectedGroup"
    (click)="onSelect(group)">
    {{group.name}}
  </li>
</ul>
<app-group-detail [group]="selectedGroup">

</app-group-detail>

app-group-detail:

<div *ngIf="group">    
  <h2>{{group.name | uppercase}} Detail</h2>
  <div>
    <label>name:
      <input [(ngModel)]="group.name" placeholder="name"/>
    </label>
    <button (click)="save()">save</button>
  </div>
</div>

现在,我的“保存项目”起作用了,成功无事了:列表中显示的对象(按名称)和编辑项目组件中的对象,然后数据库中的数据都同步。

但是后来在REST调用出错时,我正在尝试找出最 Angular 方法。当前,如果REST调用错误,我会遇到这种情况:

  • 我显示错误
  • “编辑项”组件的对象中的数据无效,必须对其进行修改或丢弃
  • “列表”组件中的数据无效,因为它也通过在底层数组中对其的引用而绑定到该对象。

现在,如果用户单击“取消”按钮会很好,但是他们也可以通过选择其他项来导航远离列表中的选定项。

什么是最好的方法?

不允许单击并强制使用“取消”按钮?

通过恢复原始值来安静地放弃编辑吗? (我将副本存储在编辑组件中)

该示例显示了使用this.location.back()的情况,但是由于REST调用不会引起我可能会放弃的新页面加载,因此我看不到它将如何工作。

2 个答案:

答案 0 :(得分:1)

我会说这取决于您的父子实现。如果您的父子视图完全不同,则不必担心未保存的更改,只需在ngOnInit()上刷新父视图并再次获取数据即可解决此问题,这是一个好习惯真实场景(可能有多个用户不断更改数据),因此您始终拥有更新的数据。但是如果您的父级在子级旁边可见并且父级无法刷新(失去所选的行焦点等),则可以在子级视图中获取数据的硬拷贝并使用该拷贝,并且在API调用成功保存时服务器上的数据,然后使用API​​返回的对象更新子组件的Input()对象。 app-group-detail.ts

  @Input() inputModel: DetailModel;
  localCopy: DetailModel;
ngOnChanges() {
    this.localCopy = JSON.parse(JSON.stringify(this.inputModel)); // or any other copy you like

    }
    save(){
    //call API to update using  this.localCopy 

    this.inputModel = // if call was successful get the reply object and put it in input
// Or better to use eventEmitters to send the object to the parent to be replaced 
// or just use eventemitters to notify the parent that it needs to be refreshed
    }
    
    
    
因此,您应该在localCopy中将app-group-detail.html用作绑定。

如果您想使用eventEmitter,则应在app-group-detail.ts中定义一个事件发射器。以下是您可以使用的两种方法:

    从子对象发出
  1. Emit事件只是为了通知父对象需要刷新列表。首先,您需要使用以下子项定义一个事件发射器

import {  EventEmitter } from '@angular/core';
@Output() public updateEventEmitter = new EventEmitter();
// then emit this event when API call is successful to notify parent
save(){
   //API call to update resource and on successful case
   this.updateEventEmitter.emit();
 }
那么在paretn上捕获此事件的方法是,当您想在父级的DOM文件中定义子级时,需要执行以下

<app-group-detail (updateEventEmitter)="updateList()" [group]="selectedGroup">

</app-group-detail>
并在parent.ts中定义updateList()函数来更新您的列表。

  1. 您可以使用相同的模式,但是将object的更新资源从子级发送到父级,以便父级替换它(以防万一)(仅在需要说明时)。 (完全如上所述,但有细微差别)。

import { EventEmitter } from '@angular/core';
@Output() dataUpdatedEventEmitter: EventEmitter<DataModel> = new EventEmitter();

save(){
// CALL API TO UPDATE
// On success emit the returned object
this.dataUpdatedEventEmitter.emit(objectToBeEmitted);
}

并在父母的DOM文件中:

<app-group-detail (dataUpdatedEventEmitter)="updateListWithItem($object)" [group]="selectedGroup">

</app-group-detail>

答案 1 :(得分:0)

我认为最好的方法是将对象的副本绑定到edit组件,因为在很多情况下都可能导致错误(例如Internet连接)。

因此,在编辑对象时,应调用edit api并告诉父对象(列表)刷新自身。之后,list组件将重新调用其api并刷新其项目。