Adding properties to the view model created by using the Knockout JS mapping plugin

前端 未结 4 867
说谎
说谎 2020-12-02 13:41

I am working through the mapping plugin example on the Knockoutjs website.

This is the example data.

Knockout JS Mapping Plugin

var data = {
         


        
相关标签:
4条回答
  • 2020-12-02 13:47

    Here is a continuation to this answer based on RP Niemeyer's solution

    This answer here is based on the solution above and from his blog--Thanks for that! I thought I should add some details because it addresses when the array is not a first level object.

     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);
    

    Note that the person is the first level object and children is a sub property of that person. The line viewModel.person = ko.mapping.fromJS(viewModel.person, mapping) wasn't intutive to me at first.

    And here is a slight variation

    The person object is an observable that is added or updated after it is originally created from the server json data.

    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;
    }
    

    Some binding code in the html

    Ultimately, you'll need to put it to some use at some point like this:

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

    Thank for your help! I couldn't have made it this far without your blog post.

    0 讨论(0)
  • 2020-12-02 13:49

    Note that to define additional computed observables on a child you will need to pass another set of mapping options

    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);
      }
    };
    
    0 讨论(0)
  • 2020-12-02 13:56

    You need to use a create method on the mapping object itself like:

    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;
      }
    };
    
    0 讨论(0)
  • 2020-12-02 14:07

    Another example based on the examples provided by Jason and RP Niemeyer.

    data is what we get after an ajax query, on which we add two nested observables (viewModel.weekly.selectedWeek and 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 讨论(0)
提交回复
热议问题