ko calculado não mostrar em vista
-
21-12-2019 - |
Pergunta
Eu tenho alguns problemas em relação à vinculação ao valor calculado.Eu estou mostrando os dados na tabela, e somando-se alguns campos.No rodapé quero exibir a soma desses campos, e a coluna vazia, bem como com o texto do total.Os valores ficam armazenados dentro de campos, bem como atualizados quando os valores dos campos referenciados alterações, mas não mostra a vista.Eu sei que fiz algo de errado com ko.calculado, mas eu não consigo identificar o que iria ser.
Código HTML:
<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>
Iin meu JS eu tenho
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'
}
]);
ajax função é apenas uma pequena wrapper em torno de us $.ajax função que usamos no projeto para obtenção de dados.
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']);
});
});
Também, makeObservable é usado para fazer os campos de um objeto observável.Como eu descobri, todos os campos que estão ligados ao calculado deve ser observável, assim, a atualização pode desencadear.
function makeObservable(model, fields) {
var ret = {};
$.each(fields(), function (index, value) {
ret[value.Field] = ko.observable(model[value.Field]);
})
return ret;
}
O que está acontecendo é desconhecido para mim.Observáveis campos do footmodel impresso, enquanto calculado não.Todos os campos de clientViewModel.modelo observável matriz de são observáveis, os valores a receber calculados, mas não é impresso.Qual é a razão por que?
Uma possível solução, tanto quanto eu vê-lo, poderia ser para acionar a função que calcula os valores a serem somados e o armazena na observáveis de campo, que devem ser impressos em OK.Mas eu gostaria de, ao invés de fazê-lo funcionar desta forma, e descobrir o que causa esse comportamento.
Obrigado.
Solução
Eu acho que você init ko.applyBindings(...)
fora da chamada ajax, o que significa que
<tr data-bind="foreach: footmodel">
<td data-bind="text: Value">
</td>
</tr>
O text: Value
liga para o original de seqüência de caracteres vazia, até que você substitua o conteúdo do Value
em ajax com um ko.computed(...)
, o sistema de ligação não sabe.
Para corrigir isto, use um if
ligação para forçar o knockout para re-analisar a ligação (a tabela completa) depois de ajax.
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
}
});