2016-04-20 13 views
1

Ich arbeite mit Angular 2 und Lodash.Angular 2 Bindung zu berechnet Getter gibt Debugfehler

ich ein Modell mit Beziehungen haben, und ich habe einen Getter wie folgt aus:

get relationsPerType() { 
    return _(this.Relations) 
     .groupBy(p => p.Type) 
     .toPairs() 
     .map(p => ({ 
      type: <MessageRelationType>p[0], 
      relations: <Relation[]>p[1] 
     })); 
} 

Bindung den Wert von relationsPerType zu einem * ngFor Richtlinie

Edit: Das ist meine Bindung:

<div *ngFor="#relationGroup of Message.relationsPerType"> 
    ... 
</div> 

gibt mir die folgende Fehlermeldung:

Expression 'Message.relationsPerType in [email protected]:8' has changed after it was checked. Previous

das scheint vollkommen richtig zu sein, denn in der Tat wird dies jedes Mal berechnet, wenn es aufgerufen wird.

In jedem Fall kann ich mir mit "berechneten" Variablen nicht vorstellen, wie Angular 2 Change Detection erkennen konnte, dass sich relationsPerType tatsächlich geändert hat. Etwas wie Markierung der Getter als unveränderlich ??

Ich nehme ein besserer Weg geben würde:

a) in einer Eigentumsrecht die berechneten Getter Werte speichern von Anfang

b) Um das übergeordnete Objekt Immutable, um für Angular Änderungen an nicht verfolgen auf Eigenschaften

Gibt es einen besseren Weg, dies zu tun?

+0

Wie binden Sie? –

Antwort

1

Nach einigem Graben fand ich einen besseren Weg Dekorateure, als a) und b) verwendet zu bieten hat, wie:

a) Ich möchte nicht die "faulen" Berechnungen verlieren, die Getterfunktionen bieten und alles zu einer Eigenschaft machen

b) Immutable eine praktikable Lösung ist, aber zu meinem Fall

also nicht anwendbar, von C# und viele Aspect Oriented Programming (siehe Postsharp) kommen, ich es endlich geschafft, eine gecached Eigenschaft Getter Dekorateur Funktion zu erstellen, die ist nur einmal pro Objekt ausgewertet:

function cachedProperty(target: any, key: string, descriptor: PropertyDescriptor) { 
    let originalGetter = descriptor.get; 
    descriptor.get = function() { 
     let cachSetted = this[`__cachedsetted${key}`]; 
     if (typeof cachSetted !== 'undefined') { 
      return this[`__cached${key}`]; 
     } 
     this[`__cachedsetted${key}`] = true; 

     return this[`__cached${key}`] = originalGetter.call(this); 
    } 
} 

danach alles, was sich ändern muss, ist die Getter mit dem @cachedProperty Dekorateur dekorieren, etwa so:

@cachedProperty 
    get relationsPerType() { 
     return _(this.Relations) 
      .groupBy(p => p.Type) 
      .toPairs() 
      .map(p => ({ 
       type: <MessageRelationType>p[0], 
       relations: <Relation[]>p[1] 
      })).value(); 
    } 

Mit diesem Decorator ändert sich das Objekt nur einmal, so dass die Angular 2 Abhängigkeitsinjektion nicht zu beanstanden ist. Außerdem verliere ich nicht die "faulen" Auswertungen, und ich füge keine Helfereigenschaften hinzu, die mein Schema ändern.

Man muss natürlich den Fall behandeln, in dem er den Cache ungültig machen will, wenn dieser alt wird. Dies würde erfordern, die Eigenschaft aus diesem zu entfernen.

0

Sie sollten den Wert zwischenspeichern und stattdessen an den zwischengespeicherten Wert binden oder eine Observable erstellen, die bei Änderungen der Daten neue Ereignisse ausgibt.

Wenn Sie an {{relationsPerType}} binden, wird jedes Mal eine neue Sammlung erstellt. Angular prüft, ob eine Änderung stattgefunden hat, und Angular sieht dies als Änderung, weil es zwei verschiedene Instanzen erhält, obwohl sie dieselben Daten enthalten könnten.

calcRelationsPerType() { 
    this relationsPerType = _(this.Relations) 
     .groupBy(p => p.Type) 
     .toPairs() 
     .map(p => ({ 
      type: <MessageRelationType>p[0], 
      relations: <Relation[]>p[1] 
     })); 
} 

dann wie diese Bindung sollte gut funktionieren:

<div *ngFor="#relationGroup of Message.relationsPerType"> 
    ... 
</div> 
+0

Hey Günter! Ich glaube, es gibt einen Tippfehler in deinem ersten Ausschnitt: 'this relationsPerType = return _ (this.Relations)' ;-) –

+0

Danke Günter. Was Sie sagen, ist tatsächlich "a) Um die berechneten Getter-Werte innerhalb einer Eigenschaft von Anfang an zu speichern" mit viel zusätzlichem Aufwand, die calcRelationsPerType() aufzurufen, bevor die Daten verknüpft werden. –

+0

Schwer zu sagen, ob es viel Aufwand von den Informationen ist, die Sie in der Frage angegeben haben. Sie müssen einen Weg finden, um es neu berechnen zu lassen, wenn die Werte das Ergebnis verändern. Die einfachste zu verstehende Lösung ist IMHO, was ich in meiner Antwort zeige. Fortgeschrittener wäre die Verwendung von Observablen. Ihr Decorator-Ansatz ist ebenfalls interessant, aber ich denke, dass das Ungültigmachen des Caches der Aufruf-Neuberechnung ziemlich ähnlich ist. –

Verwandte Themen