LA.NET [EN]

Nov 11

In my “goodbye MS AJAX post”, reader Andy asked a really interesting question: how to serialize an object which is used in a binding relationship? The main problem is that the JavaScriptSerializer doesn’t support circular references. Unfortunately, it doesn’t also provide a way for you to specify which properties should be serialized. However, the problem is still there: how do you serialize the objects used in binding relationships?

I’m still hopping that the team will fix the serializer before MS AJAX RTMs is released, but meanwhile, we’re still left with the problem. I’ve thought a little bit about it and it seems like the best option is to “suspend” the binding, serialize it, and then “resume” it again. Notice that the code you’re about to see has not been tested (it was written during my bus trip home, so it might have one or two bugs :) ,,). Let’s take a look at the example (I’ve reused most of Andy’s example and I’d like you to concentrate on the save method):

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/MicrosoftAjax/start.debug.js"
        type="text/javascript">
    </script>
    <script type="text/javascript">
        var instance = [
            { title: ''New document'',
                content: {
                    sections: [
                        { body: ''Enter text here'' },
                        { body: ''other text'' }
                    ]
                }
            }
        ];
        Sys.require([Sys.components.dataView],
            function () {
                var view = Sys.create.dataView(
                        "#maincontent",
                        { itemTemplate: ''#edit'',
                          data: instance});
        }); 
function onSave(){ var data = Sys.get("$maincontent").get_data(); var backup = {}; function cleanupMetadata(obj, propName, key) { if (obj.hasOwnProperty(propName)) { backup[key] = {}; backup[key][propName] = obj[propName]; delete obj[propName]; } } function restoreMetadata(obj, propName, key) { if (backup[key] !== undefined) { obj[propName] = backup[key][propName]; delete backup[key]; } } for (var i = 0; i < data.length; i++) { var sections = data[i].content.sections; for (var j = 0; j < sections.length; j++) { cleanupMetadata(sections[j], "_msajaxBindings",
i+
"-"+j); } } var serialized =
Sys.Serialization.JavaScriptSerializer.serialize(data);
for (var i = 0; i < data.length; i++) { var sections = data[i].content.sections; for (var j = 0; j < sections.length; j++) { restoreMetadata(
sections[i],
"_msajaxBindings", i + "-" + j); } } alert(serialized); } </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView"> <div id="edit" class="sys-template"> <label>Title</label> <input sys:value="{binding title}"/> <div sys:attach="dataview" dataview:data="{{ content.sections }}" class="sys-template"> <label>Body</label> <textarea>{binding body}</textarea> </div> </div> <div id="maincontent"></div> <button onclick="onSave()">Save</button> </body> </html>

We’re using two helper methods: cleanupMetadata and restoreMetadata. In the cleanupMetadata, we store the _msajaxBinding info in the backup object. As you can see, we’re building a key by combining the positions of the objects so that we can recover that metadata later. Yes, this isn’t really reusable code and I’d really prefer to have the serializer filter the properties which shouldn’t be serialized. However, this approach will probably be enough for now if you need to serialize an object used in a binding relationship.

And that’s it for now…

6 comments so far

  1. Andy
    9:40 pm - 11-11-2009

    Cheers for the Cleanup/Restore thoughts. Will give it a go.

    My current prototypes remove the bindings and dispose properties, then re-add a dispose array. It”s a fix of sorts for the current Library Preview! Seems like aspects of the binding and component model could cause trip-ups when used with other frameworks.

    var data = view.get_data();

    Array.forEach(data.content.sections, function(e) {
    delete e.__msajaxbindings;
    delete e.__msajaxdispose;
    });

    $.ajax({
    type: “POST”,
    contentType: “application/json”,
    url: “/document/put”,
    data: Sys.Serialization.JavaScriptSerializer.serialize(data),
    success: onSuccess,
    error: onError
    });

    // if refresh call needed in app __msajaxdispose must be an array
    // MicrosoftAjaxComponentModel.debug.js line 1173
    Array.forEach(data.content.sections, function(e) {
    e.__msajaxdispose = [];
    });

    view.refresh();

  2. luisabreu
    9:25 am - 11-12-2009

    hum…Andy, I”m not sure if I follow…I mean, I was under the impression that __msajaxdispose is added to UI elements (ie, HTML elements)…am i wrong?

  3. Andy
    11:07 am - 11-12-2009

    Yes, I assumed __msajaxdispose and __msajaxbindings would be only added to dom elements. But I think it”s a quirk of nested DataViews these get added to the actual data object. Or certainly with the bindings as in this test case, with the Beta/0910 library version.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>