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

Posted

技术标签:

【中文标题】KnockoutJS:将 Observable 属性和函数添加到映射生成的 ObservableArray 中的对象【英文标题】:KnockoutJS: Adding Observable Properties and Functions to objects in a mapping generated ObservableArray 【发布时间】:2012-01-14 03:59:43 【问题描述】:

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

这是我的目标:

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

这是我想要做的:

每个User 都有一个名为'IsActive' 的属性 - 我想data-bind 一个点击事件到每个User 对象上的一个方法,该方法可以切换这个'IsActive' 属性。

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

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

代码如下: http://jsfiddle.net/yZkSf/2/(尚未在 JS fiddle 中工作 - 但我会继续使用它,并在它工作时更新此链接)。

感谢您的帮助

【问题讨论】:

【参考方案1】:

您可以考虑多种选择。

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

类似于: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>

【讨论】:

完美! - 我接近了create: 回调,但文档侧重于修改子数组,我看不到如何扩充基础对象。非常感谢【参考方案2】:

这是我使用您和 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 -->

【讨论】:

【参考方案3】:

我找到了一种方法来做到这一点,但这意味着一旦创建了数组中的生成对象,就循环遍历它们。我更喜欢一种无需额外循环即可获得相同结果的方法。

编辑: 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);

【讨论】:

以上是关于KnockoutJS:将 Observable 属性和函数添加到映射生成的 ObservableArray 中的对象的主要内容,如果未能解决你的问题,请参考以下文章

Knockoutjs之observable和applyBindings的使用

Knockoutjs之observable和applyBindings的使用

KnockoutJS 查找 ko.observable() 长度

KnockoutJs observable array 通过计算 observable 和节流

knockoutjs 图像 src 未从 ko.observable 更新

KnockoutJS Observable 未在模板中更新