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

发布于 2024-12-23 18:23:12 字数 1330 浏览 0 评论 0原文

我正在研究 Knockoutjs 网站上的映射插件示例。

这是示例数据。

Knockout JS 映射插件

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

该示例展示了如何覆盖其中一个子项的映射,但如何我是否需要更改基础对象的映射?

例如,如果我想向 Scott 添加“FavouriteChild”属性,我该怎么做?

我假设我需要在基本映射上使用创建函数,但我无法在任何地方找到语法示例。

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

淘汰码

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

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

This is the example data.

Knockout JS Mapping Plugin

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

The example shows how to override the mapping for one of the children but how do I alter the mapping for the base object.

If for example I wanted to add a "FavouriteChild" property to Scott how would I go about it?

I assume I need to use the create function on the base mapping but I cannot find an example of the syntax anywhere.

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 : From the accepted answer below I found this to work

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

The knockout code

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌面超妹 2024-12-30 18:23:12

您需要在映射对象本身上使用 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;
  }
};

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;
  }
};
耳根太软 2024-12-30 18:23:12

这是基于 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);

请注意,该人是第一级对象,而孩子是该人的子属性。 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>

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

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.

萌面超妹 2024-12-30 18:23:12

请注意,要在子对象上定义额外的计算可观察量,您将需要传递另一组映射选项

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

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);
  }
};
农村范ル 2024-12-30 18:23:12

另一个例子基于 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);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文