We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.

Anonymous • 14 years ago

Great post, but the jsfiddle link isn't correct. it's going to the same URL as your previous post jsfiddle example. Thanks!

Ryan Niemeyer • 14 years ago

Thank you. The link is fixed!

Anonymous • 14 years ago

Great post. Just what I need. Ryan, thanks for your dedication to knockout. Any idea about the future of ko now that Steve has joined MS. They are trying to join the party with dataLink and RIA/js. I just hope that they include ko and not try to make it go away.

Ryan Niemeyer • 14 years ago

It seems that there are many influential folks at Microsoft that are familiar with and supportive of Knockout. The MIX11 KO talk appears to have been one of the most popular and buzz-worthy sessions.

If anything, I think that Microsoft may look to embrace Knockout in small ways. It could be including Knockout with a default template in MVC, adding some scaffolding that includes Knockout, creating a plug-in with some additional bindings, or even adding some better tooling support for working with it (templates and KO) in VS.

Just my opinions, but I am not worried about Knockout going away. I think that the future for Knockout is probably keeping the core lean & mean and adding necessary hooks for letting plug-ins to Knockout flourish.

The_Linux_Lich • 14 years ago

These KO utility functions are great, when you embrace MVVM, you easily reduce jquery calls by 95%. I wonder if someday we'll see something like jQueryUI ported for Knockout, like pure KO widgets.

Gregg • 14 years ago

Just wanted to take a moment to offer my heartfelt thanks for taking the time to write this stuff down. I just spent 3 hours or more trying to get a KO function to work beyond the basic demo on the official site. Between the official docs and Sanderson's MIX video, I was 80% there but I couldn't quite make it all the way. Your mapping example (above) was what I needed. I've bookmarked the site and I'll definitely be reading your archives along with new posts. Thanks again!
- Gregg

Anonymous • 14 years ago

Thanks for the blog. I was wondering it you could help me with my example. It is located at
http://jsfiddle.net/YsYuw/8/

Does right:
Displays array of data

Does Not do right:
All rows are red, only last row should be red
Knockout is not dynamicly changing remaining
Knockout is never enabling save button.
Save button does not display Json correctly.

Ryan Niemeyer • 14 years ago

Try to reconcile yours with this one: http://jsfiddle.net/rniemey...

Mainly, you need to be careful with how you access observables. You need to read the value like: var value = myObservable(). In the data-binds this is normally done for you, unless you use an expression. So, you need to do:

data-bind="css: { RowError: Remaining() != 0 }"

and

data-bind="enable: totalRemaining() == 0"

Also, in your total dependentObservable you need to access remaining like:

var value = parseInt(item.Remaining(), 10);

Finally, I added a toJSON function to your "oneCat" type and then you can use ko.toJSON when sending to the server.

Anonymous • 14 years ago

Thanks Ryan for the quick responce. That totally fixed me up. Knockout.js is very cool stuff.

Blackie • 14 years ago

do you have a way to convert all array properties of an object to observableArrays but leave the other properties as it.. seems like ko.mapping is all or nothing

thx

Ryan Niemeyer • 14 years ago

ko.mapping by default converts all arrays to observableArrays and all other properties to observables. However, you can provide a 'create' function in the options of the mapping plugin for any of your objects that could do it any way that you want. Otherwise, manually mapping it using something like ko.utils.arrayMap would be another option.

Rodrigo Rosenfeld Rosas • 14 years ago

Why can't I find those utilities in the official documentation? Specially the toJSON one...

Ryan Niemeyer • 14 years ago

The JSON APIs are documented here: http://knockoutjs.com/docum.... The other utilities are not documented at this point.

Marcus Baffa • 14 years ago

Hi Ryan,

In your article you used ko.utils.arrayMap to map data comming from the server. But if I have a JSON with a lot of records this method, I suppose, will have a very bad performance.
Could you, Please, enhance this part of your sample and use fromJSON.
I am new to Knockout but as far as I could see if you initialize a ViewModel with fromJSON all the observables
and dependentObjservables are Wipe Out and the model will have only the observables created from the properties of the JSON object.
So I have to use a Mappping Object, create a new property and create a Map with the create parameter, like this:
var mapping = {
'childObservables': {
create: function(options) {
return new myChildModel(options.data);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
(http://knockoutjs.com/docum...

MyChildModel will have to declare and implement all the dependentObservables. It is Working ok but the problem is that all dependentObservables created by MyChildModel will be in a hierarchy below childObservables. So any bindings
will have to be done like this MyViewModel.childObservables.nameOfDependenObservable().
it can be used like this but is really strange. I suppose I am forgetting something but I could not find it.
Is there a better way to use fromJSON and dependentObservables.
Thanks in advance

Ryan Niemeyer • 14 years ago

@Marcus - I tried to answer your question on the forums. https://groups.google.com/d...

Dmytrii Nagirniak • 14 years ago

The utilities in Knockout are useful. But you reinvent the wheel.

All of those functions are available in other libraries. For example Underscore.js - extremely minimal and useful. Or Sugar.js - a bit bigger and more opinionated.

You would introduce the dependency, but you would rather decrease the overall size of the JS downloaded on average client (as most of those already have the utility functions).

Even the jQuery itself has map, each etc. So why to reinvent the wheel and increase the codebase?

Ryan Niemeyer • 14 years ago

@Dmytrii - The utility functions were written to support the internals of Knockout and allow Knockout to have no dependencies (jQuery is only a dependency if you want to use the jQuery Template plugin).

Many other toolkits have similar functions and even more than KO needs. Given the simplicity and small size of the utility functions, it does not seem like there is a great reason to take on a dependency that KO has no control over.

Anonymous • 14 years ago

Any thoughts on how to use linqjs on knockout arrays?

Ryan Niemeyer • 14 years ago

One approach that you could use is to extend ko.observableArray by attaching wrapper functions to ko.observableArray.fn. The wrapper function could unwrap the observableArray, send it through a linq.js command, and then do a ToArray() on the result set.

Here is an example of adding "where" to all observableArrays: http://jsfiddle.net/rniemey...

We just added a doc page that describes this type of thing here: http://knockoutjs.com/docum...

mark • 14 years ago

Hi Ryan,

I want to bind a hot key event('del' pressed) to delete the selected item in multi-select list.

this.removeSelected = function () {
this.allItems.removeAll(this.selectedItems());
this.selectedItems([]); // Clear selection
};


I want to use jquery.hotkey.js to response the key press event.
so, how can i access the viewmodel's function outside?

Paul • 13 years ago

I think you can just call InstanceOfViewModel.removeSelected()

Ryan Niemeyer • 14 years ago

@mark- your best bet is probably using ko.dataFor or ko.contextFor, which with give you the data that would be available for binding from a DOM element. We added docs for it here: http://knockoutjs.com/docum...

Anonymous • 13 years ago

Hi Ryan,

I wonder if you can help me out...

Is there a way to observe a child properties?
I am trying to put ko.observable() on name and when they change the username it will change the address dropdownlist.

thanks much



var viewModel = function (users){
var self = this;
self.users = ko.observableArray(
ko.utils.arrayMap(users, function (user) {
user.info[0].name = ko.observable();
user.info[0].name.subscribe(function (data) {
//server side data
AjaxAddresses[0].data = "101 ave";
AjaxAddresses[0].id = "2";
user.info[0].address = AjaxAddresses[0].data;
});
return { userType: user.userType, info: ko.observableArray(user.info) };
}
));


Will

Ryan Niemeyer • 13 years ago

@Will - it looks like you are getting some help on the forums for this one. Let me know if you still have issues. I would be happy to help.

NinjaF • 13 years ago

I'm having difficulty trying to get ko.utils.compareArrays() working. I'm passing two different observableArrays. I can debug in Chrome and see that one array of objects is different than the other array of objects, but compareArrays doesn't return any results.

They are two arrays of the same type of object...of which the object in question has 6 ko.observable() properties. Am I simply expecting this to do too much?

Thanks!!

Ryan Niemeyer • 13 years ago

@NinjaF: make sure that you are passing the underlying arrays to ko.utils.compareArrays. So, you want to pass it like myArray(). Here is a sample: http://jsfiddle.net/rniemey.... Let me know if you still have issues.

NinjaF • 13 years ago

It's odd...I swear I first tested it with the () syntax and it didn't work, but now it works :). The issue I am now having is strictly based on the UI I designed. Basically, I have two equal observable arrays, one hidden. The idea is that I'm using a slightly customized version quicksand js to smoothly animate the new items into the visible array.

My logic was this...AJAX to the server, get latest array, removeAll() from hidden array, push AJAX items into hidden array, decide if hidden array was different than visible array using utils.compareArrays(), if so...animate differences so that visible array becomes the same as hidden array.

The snag seems to be that when I removeAll() from array, the compareArrays method thinks that N number were removed and N + 1 were added. It makes sense to me, but I'm wondering if there is some soft of "push" where it honors existing items and doesn't re-add them. I'll keep digging, but thanks for the great response!!

NinjaF • 13 years ago

Ryan, I created an example of what I'm doing here: http://jsfiddle.net/farina/....

I took a snapshot of my exact JSON data, and built out a similar viewmodel.

What you'll notice is that after you run the "second pass" which simulates my updated JSON data, the results show that the existing incident was both added and deleted. This is pretty much the same thing I'm seeing on my end.

Sorry for the huge JSON strings, but I wanted to give you a real picture of what I get back from the server.

Ryan Niemeyer • 13 years ago

Sorry missed this comment earlier. The issue is that the comparison is trying to validate that the before/after objects are the same. In this case they are not. For example,
var a = { name: "Ryan" };
var b = { name: "Ryan" };
var c = a === b; //false

Two objects are not equal to each other, unless they are actually the same reference.

Jose Abad Ventura • 13 years ago

Since I'm coming from other language I'll like to Know how to handle
an object send by knockout via jquery to the server: say I send the
following object to a page method on vb.net

[Object { title="PRIVMSG001"}, Object { title="PRIVMSG002"}, Object
{ title="PRIVMSG003"}, 3 more...]

down to the server in vb.net how I receive and use this json to save
on a database or work with this values.

Thanks, I hope I make my self clear on this post.

Jose Abad Ventura • 13 years ago

sorry about the object above: here is the real data

{"tasks":[{"title":"PRIVMSG001"},{"title":"PRIVMSG002"},{"title":"PRIVMSG003"},{"title":"PRIVMSG004"},{"title":"PRIVMSG005"},{"title":"PRIVMSG006"}]}

Ryan Niemeyer • 13 years ago

I don't use VB.NET, but it should be like:

<System.Web.Services.WebMethod()>
Public Shared Function Save(ByVal tasks As List(Of Thing)) As String
Return "you sent me " + tasks.Count.ToString() + " tasks."
End Function

Then, make sure that you have a ScriptManager on your page that has EnablePageMethods set to true.

Then, in JS you can do:

PageMethods.Save([{"title":"PRIVMSG001"},{"title":"PRIVMSG002"},{"title":"PRIVMSG003"},{"title":"PRIVMSG004"},{"title":"PRIVMSG005"},{"title":"PRIVMSG006"}], function (data)
{
alert(ko.toJSON(data));
});

Greg Foote • 13 years ago

Ryan,

Great Site ! You Rock!

I have a question related to select's and the value: parameter... If I have 2 types one which has a reference to the other.. It appears that you can set the value: property to an entire JSobject...

My question is what is the correct way to handle complex types referenced in a dropdown like this ?


select data-bind="options: $root.TaskTypes, value: $data.TaskType, optionsValue: 'id' , optionsText: 'Name'"

Here is a link to a fiddle that illistrates more clearly what I am talking about... Do the JS objects have to match EXACTLY ? There may be a property or two on one and not on the other... If yes, then what is the best way to handle the value binding ?

Thanks
Greg

Greg Foote • 13 years ago

Forgot to put the fiddle in the post:

http://jsfiddle.net/footegr...

Thanks
Greg

Jose Abad Ventura • 13 years ago

well man Thank you very very very much for your answer, and for the script manager (using Jquery I never use script manger, look like it is not need for .net 4 I guess or may be it is not needed at all ). said that, my next question is, Is script manager needed to call page method or web service? if so, how it work for me?, please test this and let me know if it is something not well known.

and man Thanks again

Ryan Niemeyer • 13 years ago

@Greg - If you leave out "optionsValue", then it will set your "value" equal to the actual object. However, this will be a reference to the actual object from the array that is bound to your "options".

For your case, where you want to take an id from one list and use it to find an item in another, I would set up a computed observable to locate the actual item from the id that is selected. It would look like this: http://jsfiddle.net/rniemey...

Let me know if I misunderstood your scenario. Thanks!

Ryan Niemeyer • 13 years ago

@Jose - this link has always been a good reference for calling PageMethods directly: http://encosia.com/using-jq.... The scriptmanager just builds a proxy for you, so that you can use the PageMethod object to make your call.

So, there is no problem calling it from jQuery.

Greg Foote • 13 years ago

Thanks Ryan !!

webdog • 13 years ago

I hope you're right Ryan, the thought of MS smothering KO makes me a little nervous. Long live KO. BTW: Awesome posts Ryan

Jeremy Smith • 13 years ago

Amazing blog, wish I'd found this earlier! Right now I'm using a mishmash of jquery and underscore for array and dom manipulation, and it looks like alot of equivalent methods exist in ko. Is there any gain in using as much ko as possible other than cleanliness and a slightly smaller set of .js assets (assuming underscore can be done away with)? I'm assuming that the performance is going to be roughly equivalent..

Ryan Niemeyer • 13 years ago

@Jeremy - no real advantage, if you have already committed to using another library as a dependency. In particular, Underscore has a number of helpful methods that are not included in the KO utilities (which were written to support the internals). Here is a small lib to add Underscore array methods to observableArrays: https://github.com/kamranay...

Performance will be up to the individual library. For example, if the lib called native browser methods if they are available in some cases, then you might see better performance than KO utilities functions.

MyThoughts • 13 years ago

Is there any way I can add items to an observable array, then update the array based on the key and then remove the item from the array based on the key[ID]

Basically I want to use it as a List of KeyValue pair.

Jonatanes • 13 years ago

I can debug knockout.js 
in Firebug ?

CarlosT • 13 years ago

I've been struggling with making the filtering work. I'm very new to Knockout and I think I'm missing one or several steps. What I'm trying to do is pretty simple, it's just a report that the user need to be able to filter by date range. I'm pulling data in JSON format and assigning it to an observable array like so:

self.underReview(jsonUnderReview);

I have a computed observable that for now just returns the observable array. I data bind from that computed observable and everything displays just fine.

The problem comes when I try to write a filter function. The above syntax apparently produces no hook to tie a filter function to, and when I tried to write a mapping, the bindings stopped working. I'm at a bit of a loss on how to proceed and I'd great appreciate any direction you could give me. Thanks.

Ryan Niemeyer • 13 years ago

@Carlos  Usually, you will want to create a computed observable that loops through your array and filters it based on some criteria.  If you make the criteria observable, then the computed observable will re-evaluate itself whenever the criteria changes.  Here is a sample: http://jsfiddle.net/rniemey....  If you still have problems, then maybe we can work up a sample with something closer to your code.  Hope this helps.

CarlosT • 13 years ago

Thanks Ryan, that got me what I needed. I was over complicating the syntax (I was passing in a variable I didn't need to pass in, for one thing), and your example helped me build the functions correctly. Now when the user picks the from and to dates, the report sections are filtered correctly.

Calabonga • 13 years ago

Thanks! That's very great post!

binyas kk • 13 years ago

Hi,

Thanks.

this post helped me alot....

Martyn • 13 years ago

Great help. Thank you!

Stephane • 13 years ago

The color settings for the code example is puzzling me.