KnockoutJS:向映射生成的ObservableArray中的对象添加Observable属性和函数

时间:2011-12-06 14:50:09

标签: knockout.js knockout-mapping-plugin

我是KnockoutJS的新手,我一直试图在ko.observableArray()插件创建的mapping中为生成的对象添加其他属性和方法。


这是我要去的地方:

  • 我有一个Users
  • 的JSON数组
  • 我使用映射插件
  • 创建了ko.observableArray()
  • 我有一个为每个User创建表格行的模板,到目前为止一直很好:o)


以下是我要做的事情:

每个User都有一个名为'IsActive'的属性 - 我想data-bind点击每个User对象上的方法的点击事件切换此'IsActive' } property。

This question looked promising,但似乎不必重复我必须在JS中声明整个View模型(除非我必须这样做!) - 是否可以只扩展生成的对象?

I was thinking more along these lines,其中有一种方法可以声明其他属性或方法,并让它们扩展mapping生成的对象,但本文关注的是单个对象,而不是在生成的数组中扩展对象。


以下是代码: http://jsfiddle.net/yZkSf/2/(尚未在JS小提琴中工作 - 但我会继续使用它并在我开始工作时更新此链接。)

感谢您的帮助

3 个答案:

答案 0 :(得分:13)

您可以考虑几个选项。

- 一个是使用create callback来控制“用户”对象的创建方式。您可以自己定义observable并添加额外的功能,也可以在单个用户对象上调用映射插件,然后添加额外的功能。

类似于:http://jsfiddle.net/rniemeyer/fkVaK/

- 否则,您可以在viewModel上放置“toggle”功能,然后将“user”对象传递给它。

1.3的一个好方法是使用ko.dataFor以及类似jQuery的live / delegate / on事件委托功能。就像:http://jsfiddle.net/rniemeyer/FkjNr/

//unobtrusive event handler
$(".toggle").live("click", function() {
    var user = ko.dataFor(this);
    if (user) {
       viewModel.toggleIsActive(user);
    }
});

如果您不想使用事件委派,则可以使用匿名函数直接传递项目,例如:http://jsfiddle.net/rniemeyer/GpQtN/

编辑:从2.0开始,当使用点击/事件绑定时,当前数据会自动传递给处理程序,因此您可以这样做:

<a href="#" data-bind="click: $root.toggleIsActive"><span data-bind="text: IsActive"></span></a>

答案 1 :(得分:4)

这就是我用你和Ryan的答案提出的......似乎有效。如果这是一个很好的方法,请留下反馈,因为我是Knockout的新手并且好奇自己。

JS:

$(function() {
    $.get("users/getUsers", function(r){
        var vm = ko.mapping.fromJS(r, {
            users: {
                create: function(user){
                    var methods = {
                        toggleIsActive: function(u){u.IsActive(!u.IsActive());},
                        foo: function(u){console.log(u);},
                        bar: function(u){/*whatever*/},   
                    }
                    return $.extend(ko.mapping.fromJS(user.data), methods);
                }
            }
        });
        ko.applyBindings(vm);
    }, 'json');
});

DOM:

<!-- ko foreach: users -->
   <a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->

答案 2 :(得分:0)

我找到了一种方法,但它意味着一旦创建它们就会循环遍历数组中生成的对象。我更喜欢一种方法,在没有额外循环的情况下实现相同的结果..

编辑: Like RP Niemeyer suggests in his answer!; o)

无论如何,向现有对象添加属性的一种方法是使用jQuery extend()来组合对象。

首先,在新对象中声明额外的属性和函数:

var userModel = {
    toggleIsActive: function() {
        console.log('toggleIsActive called: before: ' + this.IsActive());
        this.IsActive(!this.IsActive());
        // todo: save!
        console.log('toggleIsActive called: after: ' + this.IsActive());
    }
}

然后,在ko.mapping.fromJS()调用之后但在ko.applyBindings()调用之前,循环生成的数组中的对象并扩展它们:

viewModel.users = ko.mapping.fromJSON(/* get JSON */);

for (var i = 0; i < viewModel.users().length; i++) {
    $.extend(viewModel.users()[i], userModel);
}

ko.applyBindings(viewModel);