使用Knockout JS映射插件创建视图模型后添加属性

34

我正在按照Knockoutjs网站上的mapping插件示例进行工作。

这是示例数据。

Knockout JS Mapping Plugin

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

这个示例展示了如何覆盖其中一个子对象的映射,但我该如何修改基本对象的映射呢?

例如,如果我想要为Scott添加一个“喜爱的孩子”属性,我该怎么做呢?

我猜我需要在基础映射上使用create函数,但是我无法在任何地方找到语法示例。

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

编辑: 根据下面被接受的答案,我发现这个方法可行。

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

Knockout代码

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);
4个回答

24

你需要在映射对象本身上使用create方法,例如:

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

6
好的,我会尽力以最简洁明了的方式翻译以下内容,同时保持原意不变:“如何解释创建一个空函数并不能证明访问根级别并向其添加内容。” - Honorable Chow
更新了函数以展示在返回结果之前如何进行映射和操作。 - RP Niemeyer
我知道这是一个非常老的问题,但是我刚刚遇到它,我想提出一个建议。在KnockoutJs网站上使用create回调函数的代码示例没有解释create方法在映射对象上。如果可能的话,我建议Ryan请网站所有者用您上面的代码示例替换他们的代码示例。 - Mike Devenney

13

这里是对RP Niemeyer的解决方案进行续述的答案

本回答基于上面的解决方案和他的博客--感谢那个!我认为我应该添加一些细节,因为它解决了数组不是第一层对象时的问题。

 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);
请注意,person是第一层对象,children是该person的子属性。语句viewModel.person = ko.mapping.fromJS(viewModel.person, mapping)最初对我来说并不直观。
以下是略微变化的内容: person对象是一个可观察对象,在从服务器JSON数据创建之后添加或更新。
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;
}

在HTML中的一些绑定代码

最终,你需要像这样将其应用到某个地方:

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

非常感谢您的帮助!如果没有您的博客文章,我不可能走到这一步。


3
请注意,如果要在子级上定义其他计算观察值,则需要传递另一组映射选项。
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);
  }
};

1
我在这里寻找如何映射嵌套属性,而我认为这是最清晰的例子。如果它包括一个viewModel的示例,那对我来说就是一个完整的解决方案了。 - Mike Devenney

0

以下是基于Jason和RP Niemeyer提供的示例的另一个示例。

data是我们在ajax查询后获得的内容,我们在其中添加了两个嵌套的可观察对象(viewModel.weekly.selectedWeekviewModel.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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接