toJSON seems to be implemented incorrectly.

8 posts, 0 answers
  1. Stacey
    Stacey avatar
    56 posts
    Member since:
    Aug 2013

    Posted 21 Sep 2013 Link to this post

    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?
  2. Atanas Korchev
    Admin
    Atanas Korchev avatar
    8462 posts

    Posted 23 Sep 2013 Link to this post

    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!
  3. Stacey
    Stacey avatar
    56 posts
    Member since:
    Aug 2013

    Posted 23 Sep 2013 Link to this post

    This does not work. Changing the dataType does nothing. It still comes through incorrectly.
  4. Stacey
    Stacey avatar
    56 posts
    Member since:
    Aug 2013

    Posted 23 Sep 2013 Link to this post

    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.
  5. Atanas Korchev
    Admin
    Atanas Korchev avatar
    8462 posts

    Posted 24 Sep 2013 Link to this post

    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!
  6. Stacey
    Stacey avatar
    56 posts
    Member since:
    Aug 2013

    Posted 24 Sep 2013 Link to this post

    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() }
    });
  7. Stacey
    Stacey avatar
    56 posts
    Member since:
    Aug 2013

    Posted 24 Sep 2013 Link to this post

    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.
  8. Atanas Korchev
    Admin
    Atanas Korchev avatar
    8462 posts

    Posted 24 Sep 2013 Link to this post

    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!
Back to Top