Reputation: 435
I can create a View Model such that an array of clickable div's, with favorite/nonfavorite type icons, works correctly. I use knockout to bind the css style, which has the appropriate background image set. The Favorite function is this:
function Favorite() {
var self = this;
self.isFavorite = ko.observable();
self.toggleMe = function(ctx) {
self = ctx;
var val = self.isFavorite();
self.isFavorite(!val);
};
self.isFavoriteClass = ko.computed(function() {
if (self.isFavorite() === true)
return 'favorite';
else
return 'notFavorite';
});
}
HTML:
<div data-bind="css: {favorite: isFavorite()==true,
notFavorite: !isFavorite() } ,
event: {click: toggleMe}"
style="border:solid red;">
</div>
plnkr: http://plnkr.co/edit/LEwQd544rxrzhNyoyO5F?p=preview
However, I want to achieve the same effect with the ko.viewmodel plugin. (Well, I'd like to also be able to do is with ko.mapping :-) ) ko.viewmodel plugin reference is here:
http://coderenaissance.github.io/knockout.viewmodel/
The syntax for extending view models created with ko.viewmodel is very simple. Here is their example:
options:{
extend:{
"{root}.users[i]": function(user){
user.isDeleted = ko.observable(false);
}
}
};
viewmodel = ko.viewmodel.fromModel(model,options));
I can successfully bind data to my view model using ko.viewmodel: plnkr: http://plnkr.co/edit/afr9B8lPe1W3jCTrfH3w?p=preview
However, when I try to extend the viewmodel, so that the click-toggling behavior is also present, it fails with the messages:
Uncaught ReferenceError: Unable to process binding "with: function(){return FavoritesVm }" Message: Unable to process binding "foreach: function (){return favorites() }" Message: Unable to process binding "event: function (){return {click:toggleFavorite()} }" Message: toggleFavorite is not defined
Here is my options object, that I tried to use:
var myOptions = {
extend:{
"{root}.favorites[i]": function(favorite){
favorite.toggleFavorite = ko.computed(function() {
debugger;
// self = this;
// var val = self.isFavorite();
// self.isFavorite(!val);
// return favorite;
var val = this.isFavorite();
this.isFavorite(!val);
return favorite;
}, this);
}
}
};
plnkr: http://plnkr.co/edit/1gez79Q0kvPlRUYFcOfS?p=preview
N.B.: There a similar question to this one, on SO, regarding extending ko.viewmodel to add a ko.computed() on the {root}. However, I want to add a method to each {root}.favorite[i]. See How can I map a field computed using ko.viewmodel and http://jsfiddle.net/sublimejs/L6Wm3/8/
Upvotes: 2
Views: 177
Reputation: 39055
The problem is that you're mapping directly the favorites
array, not the FavoritesVm
, so, what you can't specify {root}.favorites[i]
, because you're in favorites
context, and not in the FavoritesVm
context. (i.e. that code tries to find a favorites
property inside the favorites
themselves)
So, to specify that you want to modify each element in favorites
, you simply has to sepcify "[i]":
var myOptions = {
extend:{"[i]": function(f) {
f.toggleFavorite = function() {
f.isFavorite(!f.isFavorite());
}
}
}
};
NOTE: besides you use too much code for a simple task, you can simply toggle the value as shown in my code, i.e. f.isFavorite(!f.isFavorite());
Click to see the working plunker
Upvotes: 1