2016-11-23 7 views
1

Ich habe eine Web-App, die auf der Aurelia CLI läuft und Knockout für seine Bindungen verwendet (weil die vorherige App, die ich nach Aurelia konvertieren ausgiebig Knockout verwendet). Dafür benutze ich das Aurelia-Knockout-Plugin ohne Probleme.Knockout Binding Problem auf Aurelia zwischengespeicherten Ansichten

I (als Test) zwei einfache Ansichten gemacht haben (und die entsprechenden Routen):

#/test1 
#/test2 

Dies sind die Ansichten:

<!-- test1.html --> 
<template view-cache="*"> 
    <div knockout> 
     <br /><br /> 
     <div data-bind="foreach: values1"> 
      <div data-bind="text: $data"></div> 
     </div> 
    </div> 
</template> 

<!-- test2.html --> 
<template view-cache="*"> 
    <div knockout> 
     <br /><br /> 
     <div data-bind="foreach: values2"> 
      <div data-bind="text: $data"></div> 
     </div> 
    </div> 
</template> 

Wie Sie aus dem html sehen können, ich bin Zwischenspeichern der Ansichten using the "view-cache" attribute, damit sie nicht neu geladen werden, wenn ich zu dieser Ansicht zurück navigiere. Die entsprechenden Modelle sind einfach wie so definiert:

//test1.js 
export class Test1 {   
    values1 = ko.observableArray([1,2,3]); 
} 

//test2.js 
export class Test2 {   
    values2 = ko.observableArray([4,5,6]); 
} 

Das ist mein Router-Konfiguration:

routes = [      
    { route: ['', 'test1'], moduleId: 'views/test1', name: 'test1' }, 
    { route: ['test2'], moduleId: 'views/test2', name: 'test2' } 
]; 

config.map(routes); 

Als ich die Seite laden, ich richtig

123 

sehen, wenn ich navigieren zu #/test2 sehe ich richtig

456 

aber wenn ich zu # test1 zurück navigieren sehe ich

112233 

wenn ich jetzt wieder gehen zu # test2 Ich sehe da auch die Zahlen ‚dupliziert‘. Und jedes Mal wenn ich hin und her gehe, werden die Zahlen immer hinzugefügt. wenn ich # test1 4mal Besuchen Sie zum Beispiel, bekomme ich

111122223333 

HINWEIS: Wenn ich die Ansichten nicht-Cache (durch Weglassen des „view-cache“ Attribut) alles ok funktioniert.

Aber ich möchte View Caching verwenden. Ich weiß aus dem, was ich gelesen habe, dass dies ein Feature ist, an dem das Aurelia-Team noch arbeitet, ich würde nur gerne wissen, ob jemand das gleiche Problem hatte und wie man es löst. Es sieht so aus, als ob die Knockout-Bindungen bei jeder Navigation zu den bereits vorhandenen hinzugefügt werden.

aktualisieren

ich die singleton decorator wie dies mit nur versucht:

import * as Framework from 'aurelia-framework'; 

@Framework.singleton() 
export class Test1 {     
    activated = false; 
    values1 = ko.observableArray([1,2,3]); 

    constructor(){ 
     console.log('constructed') 
    } 

    activate() { 
     if (this.activated) { 
      console.log('activated') 
      var val = this.values1(); 
      this.values1([]); 
      this.values1([1,2,3]); 
      console.log(this.values1()) 
     } else this.activated = true; 
    } 
} 

Was sich geändert hat, ist, dass der Konstruktor wird nicht mehr genannt, und der Zustand des Ansichtsmodell beibehalten wird (was bedeutet, , das zweite Mal, wenn ich zu # test1 navigiere, ist die Variable "activated" wahr.

Die Ausgabe der Knockout-Bindung ist dieselbe wie zuvor.

+0

Wie wäre es mit 'ko.observableArray' anstelle von' ko.observable'? –

+0

Entschuldigung ja, natürlich wollte ich ObservableArrays verwenden. Jedenfalls habe ich es einfach probiert und nichts hat sich geändert. (Ich habe den Code in der Frage korrigiert) –

+0

Wie wäre es mit dem Löschen des Arrays vor dem Füllen? wie 'values1 = ko.observableArray ([]);' und dann '[1,2,3]' dem Array 'values1 ([1,2,3]) zuweisen;' – gkb

Antwort

0

Ich denke, Sie haben möglicherweise ein logisches Problem in Ihrer Aktivierungsmethode. Ich glaube, es

if (!this.activated) ....

und bewegen Sie den

this.activated = true

in der, wenn so etwas wie dieses

activate() { if (!this.activated) { console.log('activated') var val = this.values1(); this.values1([]); this.values1([1,2,3]); console.log(this.values1()); this.activated = true; } }

+0

Nein, wenn es noch nicht aktiviert ist, möchte ich es nur aktivieren und nichts anderes. Wenn es bereits aktiviert ist, möchte ich versuchen, die Eigenschaft zurückzusetzen, um zu sehen, ob die Knockout-Bindung funktioniert. Das Problem ist, dass jeder weitere Besuch auf der Seite die beobachtbare Eigenschaft, die an den HTML-Code gebunden ist, immer wieder dieselben Werte hinzufügt (wie beschrieben). –

+0

Das liegt daran, dass Ihr Code jedes Mal, wenn das Objekt aktiviert wird, die Werte zum Array hinzufügt . Sie sollten das Array einmal initialisieren, wenn Sie das Objekt aktivieren, und bei vorherigen Aktivierungen nichts tun. –

+0

Mein Code fügt dem Array keine Werte hinzu, es setzt nur die Werte des Arrays zurück. Wie auch immer, es war nur ein zusätzlicher Test, den ich gemacht habe, wenn Sie sich meine Frage vor dem "update" -Abschnitt ansehen, es gibt keine "activate" -Logik und immer noch das gleiche Problem. –

0

Ok lesen sollte ich einen Weg zur Umgehung gefunden haben das Problem mit dem KnockoutBindable as explained here: Jetzt

//test1.html (and test2.html, same code only with variable name values1 instead of values2) 
<template view-cache="*"> 
    <div knockout> 
     <div repeat.for="item of values2"> 
      ${item} 
     </div> 
    </div> 
</template> 

//test1.js (and test2.js, same as above) 
import * as Framework from 'aurelia-framework'; 
import {KnockoutBindable} from "aurelia-knockout"; 
import {inject} from 'aurelia-dependency-injection'; 

@Framework.singleton() 
@inject(KnockoutBindable) 
export class Test2 {   
    activationData = { 
     values2: ko.observableArray([4,5,6]) 
    } 
    knockoutBindable; 

    @Framework.bindable 
    values2; 

    constructor(kb) { 
     this.knockoutBindable = kb;   
    } 

    activate() { 
     this.knockoutBindable.applyBindableValues(this.activationData, this); 
    } 
} 

wenn ich gehe hin und her werden die Werte richtig gehalten. Der Nachteil davon ist, dass ich eine zusätzliche Variable erstellen müsste, die die Knockout-Variable "spiegelt", und die in der HTML die Aurelia-Syntax verwendet, nur um dieses Problem zu vermeiden.

0

from here Genommen:

Aurelia speichert das ganze „Ansicht“ Objekt (einschließlich des Dokument-Fragment, das die html hält), wenn Sie zu einer anderen Ansicht wechseln. Wenn Sie zurückgehen, verwendet Aurelia die zwischengespeicherte Ansicht und bindet sie an Ihr neues Ansichtsmodell. Das funktioniert gut, weil alle Aurelia-Bindungen komplett neu verarbeitet werden. Aber die Templating-Engine kennt die Knockout-Syntax nicht, die auch HTML dynamisch generiert. Es behandelt es als "normales HTML" und kehrt die Änderungen von vorherigen Läufen nicht zurück.

Dieses Plugin ruft ko.cleanNode (...) auf, wenn der unbind Callback von Aurelia aufgerufen wird. Dadurch werden die zuvor vorgenommenen Änderungen wiederhergestellt (also genau das, was Sie brauchen). Leider wird der Callback zu spät aufgerufen. Die alte Ansicht ist bereits gelöst und diese Reinigung hat keine Auswirkung. Das Dokumentfragment wird wie es ist zwischengespeichert.

Verwandte Themen