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:
Users
ko.observableArray()
with the mapping pluginUser
, 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
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.
An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.
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 :).
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.
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>
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.
$(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');
});
<!-- ko foreach: users -->
<a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With