2016-05-17 5 views
1

Wie der Titel suggeriert, versuche ich, eine Elementquelle an ein berechnetes Array zu binden, das von Ergebnissen aus einem http.fetch-Aufruf aufgefüllt wird. Hier ist der Code (die interessanten Teile für diese Frage):Aurelia - binding repeat.for zu einem berechneten Array von einem Serveraufruf

Aussicht:

<tr> 
    <td repeat.for="boardItemFilter of boardItemFilters"> 
     <input if.bind="boardItemFilter.isStringFilter()" type="text" value.bind="boardItemFilter.Value & debounce:400" /> 
     <div if.bind="boardItemFilter.isCheckboxFilter()" repeat.for="sourceValue of boardItemFilter.SourceValues"> 
      <input type="checkbox" value.bind="sourceValue" checked.bind="boardItemFilter.SelectedValues" /> 
      <span textcontent.bind="sourceValue"></span> 
     </div> 
    </td> 
</tr> 

Das Viewmodel:

@computedFrom('selectedUnit') 
get boardItemFilters(){ 
    let unitName = ""; 
    if(this.selectedUnit != null){ 
     unitName = this.selectedUnit.Name; 
    } 
    return this.datacontext.fetchBoardItemFiltersByUnit(unitName) 
    .then(result => console.log(result); 
} 

Wo die fetchBoardItemFiltersByUnit() Funktion ist:

fetchBoardItemFiltersByUnit(unitName){ 
    let self = this; 
    let request = {'unitName': unitName}; 
    return this.http.fetch('BoardFilters',{ 
     method: 'post', 
     body: json(request), 
    }).then(response => response.json()) 
     .then(response => this.ExtendFilters(response)); 
} 

Die boardItemFilters() berechneten Trigger auf selectedUnit ändern sich ordnungsgemäß. Der Datacontext-Aufruf wird ausgeführt, dieser Teil funktioniert einwandfrei. Das Problem tritt auf, wenn aurelia versucht, die Eigenschaft zu binden, bevor der http.fetch ausgeführt wird. Es denkt dann, dass die Eigenschaft nicht wiederholbar ist und bricht. Nach diesen Fehlern zeigt console.log(result) das erwartete Array von Objekten an, die der Server zurückgegeben hat, aber das Ergebnis wurde der berechneten Eigenschaft nicht zugewiesen. Ich habe versucht, die Bindung manuell mit dem Signalverhalten auszulösen, ohne Glück.

Die Frage ist natürlich, was mache ich falsch? Werden die Ergebnisse nicht in der berechneten Eigenschaft gespeichert oder binden sie auf eine Weise, die nicht erwartet wird? Was wäre die richtige Lösung für dieses Problem?

Ich habe eine Menge Dinge ausprobiert, und das einzige, was zu funktionieren schien, ist eine lokale Variable zu erstellen, die die http-Ergebnisse speichert und immer diese Variable OUTSIDE die Versprechen Funktionen zurückgibt. Aber natürlich wird das immer den vorherigen Zustand zurückgeben, da es den async-Aufruf ausführt und die lokale Variable zurückgibt, bevor der Aufruf beendet wird. Das ist natürlich inakzeptabel.

Oder unterstützt Aurelia die asynchrone Bindung noch nicht?

Vielen Dank im Voraus!

EDIT: Ich habe es geschafft, in eine Lösung zu hacken, aber es ist ziemlich hässlich (mit BindingSignaler in der Versprechen-Funktion zu binden, mit dem newValue und oldValue-Vergleich, um unendliche Rechenaufrufe usw. zu vermeiden). Ich würde immer noch gerne den richtigen Weg hören, dies zu erreichen!

+0

Sie versuchen, einen HTTP-Aufruf in jeder Iteration des 'repeat.for' zu machen, die meiner Meinung nach definitiv kein guter Ansatz ist. Sie sollten den gesamten Algorithmus neu schreiben. Um berechnende Eigenschaften zu binden, müssen Sie keine Klammern verwenden, dieses 'if.bind =" boardItemFilter.isStringFilter "' ist genug –

+0

Bin ich? Ich hatte den Eindruck, dass ich das Array einmal auffüllen werde, und dann wiederhole es einfach mit dem repeat.for .. könntest du das bitte erklären? EDIT: Ich habe mir nur den Netzwerkverkehr angesehen, die API wird nur einmal aufgerufen, nicht für jede Iteration. – HotTowelie

+0

Oh, und die isStringFilter() ist eine Funktion, mit der ich das Filterobjekt erweitert habe, also werden die Klammern benötigt. Ich könnte es jedoch in eine berechnete Eigenschaft umwandeln, würde mehr Sinn ergeben. Danke :) – HotTowelie

Antwort

3

Hier ist ein Weg, um diese Art von langwieriger berechneter Operation zu lösen, die auf asynchroner verlassen Sie sich unverbindlich:

  • ändert die abhängige Eigenschaft von a nach einer normalen Eigenschaft berechnet.
  • Beobachten Sie die Abhängigkeiten manuell, um die langwierige Operation aufzurufen. Erst wenn der langwierige Vorgang abgeschlossen ist, aktualisieren Sie die abhängige Eigenschaft.

Beispiel:

export class App { 
    @bindable count; 

    constructor() { 
    this.count = 3; 
    this.computeNums(this.count) 
     .then(result => this.nums = result); 
    } 

    countChanged(value) { 
    this.computeNums(value) 
     .then(result => this.nums = result); 
    } 

    computeNums(count) { 
    let result = []; 
    for (let i = 1; i <= count; i++) { 
     result.push(i); 
    } 

    return new Promise((resolve, reject) => { 
     setTimeout(() => resolve(result), 1000); 
    }); 
    } 
} 

Hier wird nums aus count berechnet. computeNums simulieren Sie eine langwierige Operation.

Beobachten count wird durch eine Kombination von @bindable und countChanged erreicht. Möglicherweise möchten Sie stattdessen die Bindungs-Engine-API verwenden, wie in dieser question.

Voll Beispiel, die ausgeführt werden können: https://gist.run/?id=f2e26044796bfe2334d786554039aab0

+0

Mir war die @bindable - countChanged Kombination nicht bekannt. Danke, das funktioniert gut für diesen Fall. – HotTowelie

Verwandte Themen