Hemant Tank
Hemant Tank

Reputation: 1744

Issue binding date with Grid using knockoutjs

I've an editable grid and a form to add data to the grid. User can edit the grid data directly and he can use the form section to enter new entry. I've had this working fine with ASP.Net MVC combined with ajax form. I updated the whole grid html upon successful ajax postback. Nothing complex, a traditional implementation.

Now, I've been working to enhance this with knockoutjs. The idea is to persist the UI but do everything in backend so that the user experience is better with least flickers and less traffic / postback time. As expected, everything goes in backend. Here's the summary -

I've a viewModel which consists of a 'commentToAdd' object and a 'commentList' object which is as expected a list of comment objects. I bind the 'commentList' object with my Grid and the 'commentToAdd' binds with the form.

var viewModel = new commentsModel();        
$.getJSON('@Url.Action("CommentsKOVM", "Claim", new { ClaimGUID = commentObj.ClaimGUID })',
 function(data) { //upon success
    viewModel.commentToAdd = ko.mapping.fromJS(data.CommentToAdd);
    viewModel.allComments = ko.mapping.fromJS(data.AllComments, mapping);// Initial items         
  ko.applyBindings(viewModel);

Works fine. But I've a 'date' field. JSON renders it as '/Date(1224043200000)' So, I've to format it - How do I format a Microsoft JSON date? like:

<span data-bind="text:new Date(parseInt(PostedOn.toString().substr(6))).toLocaleFormat('%d/%m/%Y')"></span>

But it doesn't work because it seems that 'PostedOn' is converted into an observable! The .toString returns a function definition!

I've also tried to implement the date binding as explained by Hanselman article.

I don't seem to get my date displayed correctly in the Grid. I also tried to 'ignore the mapping' :

var mapping = {'ignore': ["PostedOn"]};

but don't know how to make it work for my child object (i.e. commentList.PostedOn).

I might not be doing it in the right manner so pls suggest or atleast help me get a correct date in my Grid.

PS: Works as expected when I use ko.observableArray(data.commentList) but it doesn't go well with edit feature.

Upvotes: 1

Views: 949

Answers (2)

Hemant Tank
Hemant Tank

Reputation: 1744

At the end it turned out that the KO.mapping.fromJS was doing its job, it converted my data.allComments (array of comments) into an "array of observables". I believe internally it converted each of its properties into observables.

So, when I accessed the date field as

PostedOn: <input type="text" data-bind="date: PostedOn" />

The custom binder for date got an observable instead of value -

ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var jsonDate = valueAccessor();

After some debugging, I updated as follows and bingo, it worked as expected!

PostedOn: <input type="text" data-bind="date: PostedOn()" />

I agree it was my misunderstanding about KO. Yet, I'm still a bit unclear about the difference between ko.mapping.fromJS and ko.Observable and more importantly when to use which?

Upvotes: 0

povilasp
povilasp

Reputation: 2396

This question here has a lot of good examples:

Handling dates with Asp.Net MVC and KnockoutJS

I personally would recommend using a custom binding as such:

var jsDateFormat = "%d/%m/%Y"; // can be something like yy-mm-dd

//...

 ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        if (value != null) {
            var jsonDate = new Date(parseInt(valueAccessor().substr(6)));
            element.innerHTML = jQuery.datepicker.formatDate(jsDateFormat, jsonDate);
        }
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    }
};

That's if you have jQuery UI and datepicker, and if not, just change:

jQuery.datepicker.formatDate(jsDateFormat, jsonDate) to your parseInt(jsonDate.substr(6))).toLocaleFormat(jsDateFormat)

And then instead of:

<span data-bind="text:new Date(parseInt(PostedOn.toString().substr(6))).toLocaleFormat('%d/%m/%Y')"></span>

Use:

Look how clean it is now! :)

You can read more about custom binding in the knockout.js docs: http://knockoutjs.com/documentation/custom-bindings.html

Upvotes: 1

Related Questions