web-dev-qa-db-fra.com

Ajout de propriétés au modèle de vue créé à l'aide du plug-in de mappage Knockout JS

Je travaille sur l'exemple du plugin de cartographie sur le site Web de Knockoutjs.

Ce sont les données d'exemple.

Plugin de mappage JS Knockout

var data = {
    name: 'Scott',
    children: [
        { id : 1, name : 'Alice' }
    ]
}

L'exemple montre comment remplacer le mappage pour l'un des enfants, mais comment puis-je modifier le mappage de l'objet de base.

Si, par exemple, je voulais ajouter une propriété "FavouriteChild" à Scott, comment procéder?

Je suppose que je dois utiliser la fonction create sur le mappage de base mais je ne trouve nulle part d'exemple de syntaxe.

var myChildModel = function(data) {
    ko.mapping.fromJS(data, {}, this);

    this.nameLength = ko.computed(function() {
        return this.name().length;
    }, this);
}

var mapping = {
    'children': {
        create: function(options) {
            return new myChildModel(options.data);
        }
    }
}

var viewModel = ko.mapping.fromJS(data, mapping);

EDIT: D'après la réponse acceptée ci-dessous, j'ai trouvé que cela fonctionnait

<span data-bind='text: AdditionalProperty'>

Le code KO

var mapping = {
    create: function (options) {
        //customize at the root level.  
        var innerModel = ko.mapping.fromJS(options.data);

        innerModel.AdditionalProperty = 'Hello World';

        return innerModel;
    }
}

var viewModel = ko.mapping.fromJS(data, mapping);

//use this as our model bindings
ko.applyBindings(viewModel);
34
fluent

Vous devez utiliser une méthode create sur l'objet de mappage lui-même comme:

var mapping = {
  //customize at the root level.  
  create: function(options) {
     //first map the vm like normal
     var vm = ko.mapping.fromJS(options.data);

     //now manipulate the returned vm in any way that you like
     vm.someProperty = "test";

     vm.someComputed = ko.computed(function() {
          return vm.first() + " " + vm.last();
     });

     //return our vm that has been mapped and tweaked
     return vm;
  }
};
24
RP Niemeyer

Voici une suite à cette réponse basée sur la solution de RP Niemeyer

Cette réponse est basée sur la solution ci-dessus et sur son blog - Merci pour ça! J'ai pensé que je devrais ajouter quelques détails car il traite lorsque le tableau n'est pas un objet de premier niveau.

 var data = {
person: {
       children: [{ id: 1, firstName: 'Scot', lastName: 'Weise'}]
    }
};

var mapping = {
    'children': {
        create: function(options) {
            return (new (function() {
                // setup the computed binding for some reason I had
                //  to use ko.dependentObservable instead of ko.computed
                // or errors showed up.
                this.fullName = ko.dependentObservable(function() {
                    return this.firstName() + ' ' + this.lastName();
                    }, this);
                    ko.mapping.fromJS(options.data, { }, this);
                })(/* call the ctor here */));
            }
        }
    };

    // Create view model and map the data object to the model.
    var viewModel = ko.mapping.fromJS(data, {});

    // update the viewModel with the mapping object that contains 
    // some a computed property(s)
    viewModel.person = ko.mapping.fromJS(viewModel.person, mapping);
    ko.applyBindings(viewModel);

Notez que la personne est l'objet de premier niveau et que les enfants sont une sous-propriété de cette personne. La ligne viewModel.person = ko.mapping.fromJS (viewModel.person, mapping) ne m'était pas intuitive au début.

Et voici une légère variation

L'objet personne est un observable qui est ajouté ou mis à jour après sa création d'origine à partir des données json du serveur.

var viewModel = {};
$(document).ready(function () {
    var person = getPerson();

    // selected person is added to the viewModel
    viewModel.selectedPerson = ko.observable(person);
    ko.applyBindings(viewModel);
});

function getPerson() { 
// you would probably pass this into the function as a parameter. 
var person =
    {
        name: 'jim',
        children: [{ id: 1, firstName: 'jane', lastName: 'bob'}]
    };

    var mapping = {
        'children': {
            create: function (options) {
                return (new (function () {
                    // setup the computed binding
                    this.fullName = ko.dependentObservable(function () {
                    return this.firstName() + ' ' + this.lastName();
                    }, this);
                    ko.mapping.fromJS(options.data, {}, this);
                })(/* call the ctor here */));
            }
        }
    };

    var result = ko.mapping.fromJS(person, mapping);
    return result;
}

n code de liaison dans le html

En fin de compte, vous devrez le mettre à profit à un moment comme celui-ci:

<div data-bind="foreach:viewModel.selectedPerson().children">
    <span data-bind="text:fullName"></span>
</div>

Merci pour votre aide! Je n'aurais pas pu arriver aussi loin sans votre blog.

13
jwize

Notez que pour définir des observables calculés supplémentaires sur un enfant, vous devrez passer un autre ensemble d'options de mappage

var mapping = {
  create: function(options) {
    //customize at the root level.  

    var mapping2 = {
      'children': {
        create: function(options) {
          //customize children also

        }
      }
    }

    //call ko.mapping.fromJS on the options.data as well with further customization
    ko.mapping.fromJS(options.data, mapping2, this);
  }
};
3
Jason

Un autre exemple basé sur les exemples fournis par Jason et RP Niemeyer.

data est ce que nous obtenons après une requête ajax, sur laquelle nous ajoutons deux observables imbriquées (viewModel.weekly.selectedWeek et viewModel.monthly.selectedMonth):

    var data = {
        "date": "2017-03-28",
        "weekly": {
            "weeks": [
                {
                    "id": "201701",
                    "label": "Week 1"
                },
                {
                    "id": "201702",
                    "label": "Week 2"
                }
            ]
        },
        "monthly": {
            "months": [
                {
                    "id": "201701",
                    "label": "01/2017"
                },
                {
                    "id": "201702",
                    "label": "02/2017"
                }
            ]
        }
    }

    var viewModelMapping = {
        create: function (options) {
            return (new (function () {
                // viewModel root level
                var mapping2 = {
                    'weekly': {
                        create: function (options) {
                            // viewModel.weekly
                            return new function () {
                                var model = ko.mapping.fromJS(options.data, {}, this);
                                model.selectedWeek = ko.observable();
                                return model;
                            };
                        }
                    },
                    'monthly': {
                        create: function (options) {
                            // viewModel.monthly
                            return new function () {
                                var model = ko.mapping.fromJS(options.data, {}, this);
                                model.selectedMonth = ko.observable();
                                return model;
                            };
                        }
                    }
                };

                ko.mapping.fromJS(options.data, mapping2, this);
            })());
        }
    };


    var viewModel = ko.mapping.fromJS(data, viewModelMapping);
    ko.applyBindings(viewModel);
0
Eric Boumendil