ko berechnet, wird nicht angezeigt
-
21-12-2019 - |
Frage
Ich habe einige Probleme mit der Bindung an den berechneten Wert.Ich zeige Daten in einer Tabelle und fasse einige Felder zusammen.In der Fußzeile möchte ich die Summe dieser Felder und die leere Spalte sowie eine mit dem Gesamttext anzeigen.Die Werte werden in den Feldern gespeichert und aktualisiert, wenn sich der Wert der referenzierten Felder ändert, sie werden jedoch nicht in der Ansicht angezeigt.Ich weiß, dass ich mit ko.computed etwas falsch gemacht habe, aber ich kann nicht genau sagen, was das sein könnte.
HTML Quelltext:
<table>
<caption><h4 class="pull-left">Caption</h4></caption>
<thead>
<tr data-bind="foreach: ColModel">
<th data-bind="text: Caption"></th>
</tr>
</thead>
<tbody data-bind="foreach: { data: model, as: 'row' }">
<tr data-bind="foreach: { data: $root.ColModel, as: 'col' }">
<td data-bind="text: row[col.Field], css: { hidden: col.InSum != false }">
</td>
<td data-bind="css: { hidden: col.InSum != true }">
<input type="number" step="any" class="input-small" data-bind="value:row[col.Field], valueUpdate: 'afterkeydown'" />
</td>
</tr>
</tbody>
<tfoot>
<tr data-bind="foreach: footmodel">
<td data-bind="text: Value">
</td>
</tr>
</tfoot>
</table>
In meinem JS habe ich
clientViewModel.ColModel = ko.observableArray([
{
Caption: 'cap1',
InSum: false,
Field: 'FLD1'
},
{
Caption: 'cap2',
InSum: false,
Field: 'FLD2'
},
{
Caption: 'capsum1',
InSum: true,
Field: 'fldsum1'
},
{
Caption: 'capsum2',
InSum: true,
Field: 'fldsum2'
}
]);
clientViewModel.model = ko.observableArray();
clientViewModel.footmodel = ko.observableArray([
{
Value: '',
IsSum: false
},
{
Value: 'total',
IsSum: false
},
{
Value: '',
IsSum: true,
SumField: 'fldsum1'
},
{
Value: '',
IsSum: true,
SumField: 'fldsum2'
}
]);
Die Ajax-Funktion ist nur ein kleiner Wrapper um die $.ajax-Funktion, die wir im Projekt zum Abrufen von Daten verwenden.
ajax('modelurl'),
'GET',
true,
function (data, status) {
$.each(data.Records, function (index, value) {
var observableValue = makeObservable(value, clientViewModel.ColModel);
clientViewModel.model.push(observableValue);
});
$.each(clientViewModel.footmodel(), function (index, value) {
if (value['IsSum']) {
clientViewModel.footmodel()[index]['Value'] = ko.computed(function () {
var sum = 0;
$.each(clientViewModel.model(), function (i, data) {
sum = parseFloat(sum) + parseFloat(data[value['SumField']]());
});
return sum.toString();
}, clientViewModel);
}
else
value['Value'] = ko.observable(value['Value']);
});
});
Außerdem wird makeObservable verwendet, um die Felder eines Objekts beobachtbar zu machen.Wie ich herausgefunden habe, sollten alle mit der Berechnung verbundenen Felder beobachtbar sein, sodass die Aktualisierung ausgelöst werden kann.
function makeObservable(model, fields) {
var ret = {};
$.each(fields(), function (index, value) {
ret[value.Field] = ko.observable(model[value.Field]);
})
return ret;
}
Was los ist, ist mir unbekannt.Beobachtbare Felder des Fußmodells werden ausgedruckt, berechnete jedoch nicht.Alle Felder des beobachtbaren Arrays clientViewModel.model sind beobachtbar, die Werte werden berechnet, aber nicht ausgedruckt.Was ist der Grund dafür?
Eine mögliche Lösung könnte meiner Meinung nach darin bestehen, die Funktion auszulösen, die die zu summierenden Werte berechnet und im beobachtbaren Feld speichert, das in Ordnung ausgedruckt werden sollte.Aber ich würde es lieber so machen und herausfinden, was dieses Verhalten verursacht.
Danke.
Lösung
Ich schätze, du hast es initiiert ko.applyBindings(...)
außerhalb des Ajax-Aufrufs, was bedeutet
<tr data-bind="foreach: footmodel">
<td data-bind="text: Value">
</td>
</tr>
Der text: Value
bindet an die ursprüngliche leere Zeichenfolge, auch wenn Sie den Inhalt ersetzen Value
in Ajax mit a ko.computed(...)
, das Bindungssystem weiß es nicht.
Um das Problem zu beheben, verwenden Sie eine if
Bindung, um Knockout zu erzwingen, um die Bindung (die gesamte Tabelle) nach Ajax erneut zu analysieren.
HTML
<!-- ko ifnot: loading -->
<table> ... </table>
<!-- /ko -->
JS
clientViewModel.loading = ko.observable(false);
// begin ajax
clientViewModel.loading(true); // ko removes the table from DOM
$.ajax({...,
success: function(data, status) {
//... built your ko.computed
},
complete: function() {
// finish ajax
clientViewModel.loading(false); // ko re-creates the table in DOM
}
});