KnockoutJS: Adding Observable Properties and Functions to objects in a mapping generated ObservableArray

Andrew picture Andrew · Dec 6, 2011 · Viewed 11.4k times · Source

I'm new to KnockoutJS, and I'm stuck trying to add additional properties and methods to the generated objects in the ko.observableArray() as created by the mapping plugin.


Here's where I'm up to:

  • I have a JSON array of Users
  • I've created the ko.observableArray() with the mapping plugin
  • I've got a template that creates table row for each User, so far so good :o)


Here's what I'm trying to do:

Each User has a property called 'IsActive' - I'd like to data-bind a click event to a method on each User object that toggles this 'IsActive' property.

This question looked promising, but it seems like unnecessary duplication to me to have to declare the entire View Model in JS (unless that's the way I have to do it!) - is it possible to just extend the generated object?

I was thinking more along these lines, where there's a way to declare additional properties or methods, and have them extend the mapping generated objects, but this article is concerned with single objects rather than extending objects in a generated array.


Here's the code: http://jsfiddle.net/yZkSf/2/ (not yet working in JS fiddle - but I'll keep playing with it and update this link when I get it working).

Thank you for your help

Answer

RP Niemeyer picture RP Niemeyer · Dec 6, 2011

There are several options that you could consider.

-One is to use the create callback to control how your "user" objects get created. You can either define the observables yourself and add extra functionality or call the mapping plugin on the individual user object and then add extra functionality.

Would be something like: http://jsfiddle.net/rniemeyer/fkVaK/

-Otherwise, you can place the "toggle" function on your viewModel and then pass the "user" object to it.

A nice way with 1.3, is to use ko.dataFor along with something like jQuery's live/delegate/on event delegation functionality. Would be like: http://jsfiddle.net/rniemeyer/FkjNr/

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

If you don't want to use event delegation, then you can pass the item directly using an anonymous function like: http://jsfiddle.net/rniemeyer/GpQtN/

EDIT: as of 2.0, the current data automatically gets passed to the handler when using click/event bindings, so you can just do:

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