Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 346
Andrew Avatar asked Dec 06 '11 14:12

Andrew


People also ask

What is Ko observable ()?

An observable is useful in various scenarios where we are displaying or editing multiple values and require repeated sections of the UI to appear and disappear as items are inserted and deleted. The main advantage of KO is that it updates our UI automatically when the view model changes.

What is observableArray?

An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.

How do you update items in observableArray Knockout?

You should look at defining the object structure for each element of your array and then add elements of that type to your observable array. Once this is done, you will be able to do something like item. productQuantity(20) and the UI will update itself immediately. EDIT Added the function provided by the OP :).

How do you assign a value to observable Knockout?

To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.


2 Answers

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>
like image 80
RP Niemeyer Avatar answered Oct 24 '22 17:10

RP Niemeyer


This is what I came up with using both your and Ryan's answers... seems to work. Please leave feedback, as I am new to Knockout and curious myself, if this is a good approach.

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 -->
like image 33
Jordan Arseno Avatar answered Oct 24 '22 18:10

Jordan Arseno