我有一个处理单一类型对象的应用。我使用服务管理对象的状态。在一个组件中,我显示对象。从这里,您可以单击字段以在另一个组件中编辑它们。您还可以单击按钮将新项目添加到字段中,也可以删除项目。
大部分时间这种方法都可以正常运行,但有时它会在没有任何错误消息的情我点击删除或编辑按钮或字段,没有任何反应。点击处理程序已损坏(我已在控制台中检查过此项)。这通常在我添加或删除数组后发生。
这非常令人困惑,因为当我添加一个元素时,我使用http来确保它被保存到数据库中,然后只有在返回带有新Droplet的observable之后我才让angular更新显示。显示屏始终更新。然而,有时显示更新,但Augury没有意识到,这是非常奇怪的。所以我将添加一个提示,例如,提示将在数据库中可见,返回并且视图将被更新,但是Augury将不会在组件中看到它。
它也不一致。有时候工作得很好。
以下是视图中的一些示例代码。
<h4>Hints (optional)</h4>
<button class="btn btn-sm" [routerLink]="['/create/create5']">Add New</button>
<div *ngIf="droplet.hints.length < 1">None</div>
<div class="row" *ngFor="let hint of droplet.hints; let i=index">
<div class="hint col-md-10" (click)="selectHint(i)">
<span [innerHTML]="hint.content || empty"></span>
<span (click)="removeElement(i, 'hint')" class="pull-right glyphicon glyphicon-remove" aria-hidden="true"></span>
</div>
</div>
<h4>Tags
<div class="progress-marker" [class.complete]="droplet.tags.length > 0"></div>
<div class="progress-marker" [class.complete]="droplet.tags.length > 1"></div>
<div class="progress-marker" [class.complete]="droplet.tags.length > 2"></div>
</h4>
<button class="btn btn-sm" [routerLink]="['/create/create6']">Add New</button>
<div *ngIf="droplet.tags.length < 1">None</div>
<br>
<button *ngFor="let tag of droplet.tags; let i=index" type="button" class="btn btn-default btn-sm" (click)="removeElement(i, 'tag')">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> {{ tag.tag }}
</button>
有几个这样的字段,但一般来说,带有* ngIf的字段是导致问题的字段。正如我所说的,如果我在数组中添加,删除或编辑元素,它就可以工作并且模板会更新,但是在此之后数组中通常没有任何东西可以工作(尽管非数组工作正常)。
相关的组件代码如下所示:
import { Component, OnInit } from '@angular/core';
import { Droplet } from '../droplet';
import { DropletService } from '../droplet.service';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs/Rx';
import { HttpService } from '../http.service';
export class ShowDropletComponent implements OnInit {
droplet: Droplet;
constructor(
private dropletService: DropletService,
private router: Router,
private httpService: HttpService
) { }
ngOnInit() {
this.droplet = this.dropletService.getCurrentDroplet();
this.dropletService.pushedDroplet.subscribe(
droplet => this.droplet = droplet
)
}
//using dummy to ensure element not updated unless returned from server
removeElement(index, element) {
console.log("remove clicked");
let dummy = this.droplet;
if (element === "explanation") {
this.router.navigate(['create/create3']);
dummy.explanations.splice(index, 1);
} else if (element === "question") {
this.router.navigate(['create/create4']);
dummy.questions.splice(index, 1);
} else if (element === "hint") {
this.router.navigate(['create/create5']);
dummy.hints.splice(index, 1);
} else if (element === "tag") {
dummy.tags.splice(index, 1);
}
this.httpService.saveDroplet(dummy)
.subscribe(
(droplet: Droplet) => {
this.dropletService.updateCurrentDroplet(droplet);
}
);
}
editThis(field) {
if (field === "description") {
this.router.navigate(['create/create2']);
} else if (field === "name") {
this.router.navigate(['create/create1']);
}
}
selectExplanation(index) {
console.log("select exp clicked");
this.router.navigate(['create/create3', index]);
}
selectQuestion(index) {
console.log("rselect q clicked");
this.router.navigate(['create/create4', index]);
}
selectHint(index) {
console.log("select hint clicked");
this.router.navigate(['create/create5', index]);
}
}
我的猜测是,这与* ng在视图中更新数组有关,但是索引没有正确更新或者点击处理程序正在破坏,但它不仅仅是模板特定部分的那些。我很茫然。
答案 0 :(得分:1)
在操作*ngFor
指令中的项时,重要的是添加一个返回唯一索引的trackBy
函数 - 因此指令可以在删除/添加项时跟踪它们的属性。
假设您的tag.tag
是唯一的,您可以这样写*ngFor
:
<button *ngFor="let tag of droplet.tags; let i=index; trackBy: tag.tag" type="button"...
答案 1 :(得分:0)
对此的解决方案很奇怪。我将组件并排放置,左侧显示编辑表单,右侧编辑或创建了Droplet。您可以单击右侧的按钮或字段,左侧将显示相应的表单以进行编辑。问题是,如果显示的Droplet在左侧组件的右下方延伸了字段,则点击将无法工作,浏览器只会滚动到屏幕顶部。我不知道为什么会发生这种情况,但是在同一个视口内强行解决了这个问题。