2017-01-03 3 views
1

Ich habe eine App, die sich mit einem einzigen Objekttyp befasst. Ich verwalte den Zustand des Objekts mit einem Service. In einer Komponente zeige ich das Objekt an. Von hier aus können Sie auf Felder klicken, um sie in einer anderen Komponente zu bearbeiten. Sie können auch auf Schaltflächen klicken, um einem Feld neue Elemente hinzuzufügen und Elemente zu löschen.Angular 2 Vorlage aktualisiert aber brechen Klickhandler

Die meiste Zeit funktioniert das gut, aber manchmal bricht es ohne irgendwelche Fehlermeldungen. Ich klicke auf die Schaltflächen zum Löschen oder Bearbeiten und es passiert nichts. Die Click-Handler sind defekt (ich habe das in der Konsole überprüft). Dies geschieht normalerweise, nachdem ich ein Array hinzugefügt oder aus einem Array gelöscht habe.

Das ist sehr verwirrend, denn wenn ich ein Element hinzufüge, benutze ich http, um sicherzustellen, dass es in der Datenbank gespeichert wird, und erst nachdem das Observable mit dem neuen Droplet zurückgegeben wurde, lasse ich die Anzeige angular aktualisieren. Und das Display wird immer aktualisiert. Manchmal wird die Anzeige jedoch aktualisiert, aber Augury erkennt nicht, was sehr seltsam ist. Also werde ich einen Hinweis hinzufügen, zum Beispiel wird der Hinweis in der Datenbank sichtbar sein, zurückgegeben werden und die Ansicht wird aktualisiert, aber Augury wird es in der Komponente nicht sehen.

Es ist auch inkonsistent. Manchmal funktioniert es gut.

Hier ist ein Beispielcode aus der Ansicht.

<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> 

Es gibt mehrere Felder wie dies aber in der Regel diejenigen, die mit * ngIf sind diejenigen, die Probleme verursachen. Wie ich gesagt habe, wenn ich ein Element in dem Array hinzufüge, entferne oder bearbeite, funktioniert es und die Vorlage wird aktualisiert, aber oft arbeitet danach nichts mehr in den Arrays (obwohl die Nicht-Arrays gut funktionieren).

Die entsprechende Komponente Code sieht wie folgt aus:

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]); 
    } 

} 

Meine Vermutung ist, dass es etwas ist, mit dem * ngFor Aktualisierung des Array in der Ansicht zu tun, sondern entweder der Index Aktualisierung nicht richtig oder die Klickhandler sind brechen, aber es ist nicht nur mit denen in diesem bestimmten Teil der Vorlage. Ich bin ratlos.

Antwort

1

Bei der Bearbeitung von Elementen in einer *ngFor Direktive ist es wichtig, eine trackBy Funktion hinzuzufügen, die einen eindeutigen Index zurückgibt - damit die Direktive diese Eigenschaft beim Entfernen/Hinzufügen von Elementen verfolgen kann.

Angenommen, Ihre tag.tag ist einzigartig Sie Ihre *ngFor wie dieser Stelle schreiben konnte:

<button *ngFor="let tag of droplet.tags; let i=index; trackBy: tag.tag" type="button"... 
+0

Es scheint, dass Sie jetzt eine Funktion verwenden müssen, wenn Sie trackBy verwenden, was ich getan habe, die ID jedes Artikels zurückgeben. Aber leider hilft es nicht. Ich habe die gleichen Probleme. – Finnjon

0

Die Lösung für dieses ungerade war. Ich hatte Komponenten nebeneinander mit Bearbeitungsformularen auf der linken Seite und dem Tropfen, der bearbeitet oder auf der rechten Seite erstellt wurde. Sie könnten auf die Knöpfe oder Felder auf der rechten Seite klicken und das entsprechende Formular würde auf der linken Seite erscheinen, um es zu bearbeiten. Das Problem bestand darin, dass, wenn der angezeigte Tropfen Felder aufweist, die sich rechts weit unterhalb der Komponente auf der linken Seite erstrecken, die Klicks nicht funktionieren würden und der Browser einfach zum oberen Bildschirmrand scrollte. Ich weiß nicht, warum das passiert ist, aber wenn ich alles innerhalb des gleichen Viewports erzwinge, ist das Problem gelöst.

Verwandte Themen