This is a migrated thread and some comments may be shown as answers.

toJSON seems to be implemented incorrectly.

7 Answers 302 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Stacey
Top achievements
Rank 1
Stacey asked on 22 Sep 2013, 04:17 AM
When using the toJSON function on ObservableObject, there is a distinct issue with the way it deserializes. 

The way toJSON outputs will yield to this kind of behavior in HTTP Posts.
Name                 | Value
items[0][Name]       | Name 1
items[0][Id]         | a
items[1][Name]       | Name 2
items[1][Id]         | b
This is incorrect, though. It should be coming in like this ...
items[0].Name       | Name 1
items[0].Id         | a
items[1].Name       | Name 2
items[1].Id         | b
The way Kendo's toJSON function works will essentially make it completely impossible to send data over the wire, because the values of properties will get stripped away. This is pretty easy to fix, as even the most basic behavior in Knockout does not do this. 

This is a pretty egregious problem, as it makes it very difficult and confusing to rely on the tools, because now I know that anything that Kendo's internals use that implements toJSON is completely unsuitable for any kind of method calls.

Is there any chance this can get fixed soon?

7 Answers, 1 is accepted

Sort by
0
Atanas Korchev
Telerik team
answered on 23 Sep 2013, 08:23 AM
Hi Stacey,

This is the default format used by jQuery to serialize nested objects when making an ajax request. The Kendo UI DataSource relies entirely on jQuery.ajax when doing ajax requests. The problem isn't related with the way the toJSON method of the ObservableObject works.

 The function used by jQuery.ajax to do serialization is jQuery.param. Here is a live demo which shows how it behaves with nested objects: http://jsbin.com/oxorUvu/1/edit. It yields the exact same format you have seen.

 There are two ways to deal with this behavior:

1. Send your data in JSON format:

<script>
var dataSource = new kendo.data.DataSource({
  transport: {
    create: {
      dataType: "jsonp" // "jsonp" is required for cross-domain requests; use "json" for same-domain requests
    },
    parameterMap: function(data, type) {
      return kendo.stringify(data);
    }
  },
  batch: true,
  schema: {
    model: { id: "ProductID" }
  }
});
dataSource.add( { ProductName: "New Product" });
dataSource.sync();
</script>

2. Implement a custom transport for your data source and do the serialization manually in the desired format:
<script>
var dataSource = new kendo.data.DataSource({
  transport: {
    read: function(options) {
      // make JSONP request to http://demos.kendoui.com/service/products
      $.ajax({
        dataType: "jsonp", // "jsonp" is required for cross-domain requests; use "json" for same-domain requests
           data: /* serialize your data here */,
        success: function(result) {
          // notify the data source that the request succeeded
          options.success(result);
        },
        error: function(result) {
          // notify the data source that the request failed
          options.error(result);
        }
      });
    }
  }
});
dataSource.fetch(function() {
  console.log(dataSource.view().length); // displays "77"
});
</script>

Regards,
Atanas Korchev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Stacey
Top achievements
Rank 1
answered on 24 Sep 2013, 12:01 AM
This does not work. Changing the dataType does nothing. It still comes through incorrectly.
0
Stacey
Top achievements
Rank 1
answered on 24 Sep 2013, 12:11 AM
The way you are showing to use parameterMap there, it is not working either. 

$.ajax({
    type: "POST",
    url: "/administrator/attendance/save2",
    dataType: "jsonp",
    parameterMap: function (data, type) {
        return {
            model: kendo.stringify(data)
        }
    }
});
This just yields a null result, unfortunately.
0
Atanas Korchev
Telerik team
answered on 24 Sep 2013, 06:26 AM
Hi Stacey,

 The code you have pasted is not valid. It is a mix of the solutions I have provided. The $.ajax doesn't have a parameterMap method. The Kendo data source does.

 How you would implement the same if Kendo UI weren't involved? How would you send a complex object to your action method? I am sure the same approach could be easily used with Kendo UI observable objects.

Regards,
Atanas Korchev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Stacey
Top achievements
Rank 1
answered on 24 Sep 2013, 11:41 AM
Well, in KnockoutJS, all I ever had to do was call ".toJSON" and it sent to the action methods just fine.

I think the problem is that you guys have deceptively named this method. It is not "toJSON", it is "toJS", or "toJavascript".

Your ".toJSON" method converts an observable into raw Javascript without all of the other stuff. This is fine, since it is often desired, but it is certainly different than "toJSON".

I would expect a 'toJSON' method to behave the same way kendo.stringify works, only sound far less silly than "stringify" and account for any awkward behavior imposed by the existence of observable object.

This code works just fine in KnockoutJS, also, so ... this is how I would do it.
$.ajax({
    type: "POST",
    url: "/administrator/attendance/save2",
    dataType: "json",
    data{ model: viewModel.toJSON() }
});
0
Stacey
Top achievements
Rank 1
answered on 24 Sep 2013, 11:45 AM
Don't get me wrong. I can get what I need done using the stringify method it seems, but that seems obtuse and silly.

I absolutely love the Kendo framework, but there are just little quirks and convention mistakes like this that make me shake my head and wonder what the developers were thinking at the time. I'm unclear how anyone believed that this method is the same as pure JSON, as JSON is usually only useful when sent over the word, and rarely has any place in actual javascript code. Because within actual javascript code, it is just "javascript".

I suppose the only logical argument I can reach is that converting everything to raw javascript as the "toJSON" method facilitates the process by giving you a
simple object that you can convert by yourself.

But I don't agree, to be honest. I would much rather see "toJSON" renamed to "toJS" like it is in KnockoutJS, and then an actual "toJSON" method implemented that essentially overloaded or called upon the stringify method, with any customization Kendo needed for its observables.
0
Atanas Korchev
Telerik team
answered on 24 Sep 2013, 11:54 AM
Hi,

 There seems to be some misunderstanding. The toJSON method is something used by JSON.stringify to perform JSON serialization. We didn't pick neither the toJSON name nor the stringify name - it is the standard. The kendo.stringify method is a wrapper for JSON.stringify because the latter isn't available in IE7. So we are not considering those convention mistakes - those are official conventions defined by the W3C and supported by all modern browsers.

The code you have posted won't work. To post JSON via $.ajax the data option must be a string and not an object. Otherwise you would end up with the initial problem being discussed here. To post JSON to ASP.NET MVC you need to serialize your data as JSON and pass it as the data option of $.ajax. More details can be found here: http://stackoverflow.com/questions/14752522/post-json-to-asp-net-mvc-4-action-from-jquery

Regards,
Atanas Korchev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Tags
General Discussions
Asked by
Stacey
Top achievements
Rank 1
Answers by
Atanas Korchev
Telerik team
Stacey
Top achievements
Rank 1
Share this question
or