Pregunta

Tengo algunos problemas con respecto a la vinculación al valor calculado.Estoy mostrando datos en la tabla y resumiendo algunos campos.En el pie de página quiero mostrar la suma de esos campos y la columna vacía, así como una con el texto del total.Los valores se almacenan dentro de los campos y se actualizan cuando cambia el valor de los campos a los que se hace referencia, pero no se muestran en la vista.Sé que hice algo mal con ko.computed, pero no puedo precisar qué podría 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>

En mi JS tengo

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'
    }
]);

La función ajax es solo una pequeña envoltura de la función $.ajax que usamos en el proyecto para recuperar datos.

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']);
        });
});

Además, makeObservable se utiliza para hacer observables los campos de un objeto.Como descubrí, todos los campos que están conectados a lo calculado deben ser observables, por lo que la actualización puede activarse.

function makeObservable(model, fields) {
    var ret = {};
    $.each(fields(), function (index, value) {
        ret[value.Field] = ko.observable(model[value.Field]);
    })
    return ret;
}

Lo que está pasando es desconocido para mí.Los campos observables del modelo de pie se imprimen, mientras que los calculados no.Todos los campos de la matriz observable clientViewModel.model son observables, los valores se calculan, pero no se imprimen.¿Cuál es la razón para eso?

Una posible solución, hasta donde yo lo veo, podría ser activar la función que calcula los valores a sumar y los almacena en el campo observable, que debería imprimirse correctamente.Pero prefiero hacer que funcione de esta manera y descubrir qué causa este comportamiento.

Gracias.

¿Fue útil?

Solución

Supongo que iniciaste ko.applyBindings(...) fuera de la llamada ajax, lo que significa

<tr data-bind="foreach: footmodel">
    <td data-bind="text: Value"> 
    </td>
</tr>

El text: Value se une a la cadena vacía original, incluso si reemplaza el contenido de la Value en ajax con un ko.computed(...), el sistema vinculante no lo sabe.

Para solucionarlo, utilice un if vinculante para forzar el knockout para volver a analizar el enlace (toda la tabla) después 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
  }
});
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top