Question

J'ai quelques problèmes concernant la liaison à la valeur calculée.J'affiche les données dans un tableau et je résume certains champs.En pied de page, je souhaite afficher la somme de ces champs, la colonne vide, ainsi qu'une colonne avec le texte du total.Les valeurs sont stockées dans les champs et mises à jour lorsque la valeur des champs référencés change, mais elles ne s'affichent pas dans la vue.Je sais que j'ai fait quelque chose de mal avec ko.computed, mais je ne peux pas identifier ce que cela serait.

Code 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>

Dans mon JS, j'ai

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 fonction ajax n'est qu'un petit wrapper autour de la fonction $.ajax que nous utilisons dans le projet pour récupérer des données.

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

De plus, makeObservable est utilisé pour rendre les champs d'un objet observables.Comme je l'ai découvert, tous les champs connectés au calcul doivent être observables, ainsi la mise à jour peut se déclencher.

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

Ce qui se passe m'est inconnu.Les champs observables du modèle de pied sont imprimés, alors que les champs calculés ne le sont pas.Tous les champs du tableau observable clientViewModel.model sont observables, les valeurs sont calculées, mais elles ne sont pas imprimées.Quelle est la raison de ceci?

Une solution possible, à mon avis, pourrait être de déclencher la fonction qui calcule les valeurs à additionner et les stocke dans le champ observable, qui devrait être imprimé correctement.Mais je préfère que cela fonctionne de cette façon et découvrir les causes de ce comportement.

Merci.

Était-ce utile?

La solution

Je suppose que tu es initialisé ko.applyBindings(...) en dehors de l'appel ajax, ce qui signifie

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

Le text: Value se lie à la chaîne vide d'origine, même si vous remplacez le contenu du Value en ajax avec un ko.computed(...), le système de liaison ne le sait pas.

Pour le réparer, utilisez un if liaison pour forcer knockout à ré-analyser la liaison (la table entière) après 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
  }
});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top