2005 2006 2007 2008 2009 2010 2011 2015 2016 2017 aspnet azure csharp debugging elasticsearch exceptions firefox javascriptajax linux llblgen mongodb powershell projects python security services silverlight training videos wcf wpf xag xhtmlcss

JavaScript Repeater Data Binding

In a previous post, I wrote about a way to convert JSON to XAML. The sample I provided with that post didn't really stop with a simple conversion example, but it also demonstrated how to create an use a simple JavaScript data binding repeater. It's just something I threw together in two minutes to bind an array of objects to a div to basically do in JavaScript/XHTML what ASP.NET does with the Repeater control. I think many people will be interested in this technique to see how they can bind data to a browser in a more efficient way.

As far as my requirements, I wanted this to be like ASP.NET in that the data is bound from a data source matching the fields in the data source objects to the data fields declared in this repeater and after all is said and done, the original declarative code should disappear. As far as the data source, I wanted it to be a series of the same type of object... kind of like a generic List.

So, to start off with, I simply declared the code that I wanted to write as the client. Some people call this the 'Sellsian' method (after Chris Sells at Microsoft), though I simply call it... common sense (as I honestly suspect Chris would too!). So, here is the declarative code I wanted to write for my data binding:

<div id="rptData">
    <h2>Title</h2>
    <div id="title" class="bind"></div>

    <h2>XAML Output </h2>
    <div id="output" class="bind"></div>
</div>

In this situation the data source fields are matched to element with the bind class and the element id. This is much like <%#Bind("") %> in ASP.NET.

On the other side, I would like my data source to be in JSON format and I would like to be able to bind in a way that 'feels' like a static class. Here is what I decided on:

var dataSource = [{
        title: 'Ellipse',
        output: Xaml.CreateXamlFromJSON(jsonElement1)
    }, {
        title: 'Rectangle',
        output: Xaml.CreateXamlFromJSON(jsonElement2)
    }, {
        title: 'Canvas',
        output: Xaml.CreateXamlFromJSON(jsonElement3)
    }
];

DataBinder.BindTextRepeater(D('rptData'), dataSource);

In the sample above you can see that I have a data source with 3 objects with the object being defined with the interface of a string field named 'title' and another string field named 'output'. Furthermore, I wanted to call the method what it is: a text repeater, not a fancy object repeater (though building that shouldn't be much more difficult), so my static method is called BindTextRepeater and accepts the declarative repeater object and the data source as parameters. In my examples I use the D('id') syntax where D is simply an alias for document.getElementById. I know some people use a dollar sign for that, but that just looks really weird to me.

Now onto the code. Here is the basic shell:

var DataBinder = {
    BindTextRepeater: function(obj, ds) {

    }
}

The first thing we do in this situation is look at the data source and see what the objects look like. For this we simply need to create an array to record what fields we are looking at and iterate through the object to record it's fields. Put another way... we simply need to do simple JavaScript reflection and record the object interface, something that's incredibly simple in JavaScript.

var fields = new Array( );
for(var f in ds[0]) { fields.push(f); }

Now that we know what the object looks like, let's iterate through the datasource and bind each field to it's proper place in the repeater. This is what the rest of the method does and it should be fairly self explanatory, except for the following things:

First, I said that data is bound to fields with the 'bind' class. What if you had your own class on it? That's not a problem. JavaScript classes are a bit like .NET interfaces (where as JavaScript ids are a bit like .NET classes), so you can "apply" (or implement in .NET) a few of them. So, if you wanted the apply the class "message-log" to the bindable element, you would simply have the following:

<div class="bind message-log"></div>

In this case this is possible because I'm simply checking to see if the class STARTS with "bind", rather than simply checking to see if it IS "bind":

if(obj.childNodes[e].id && obj.childNodes[e].className && obj.childNodes[e].className.substring(0, 4) == 'bind') {
    /* ... */
}

Second, if the element if found to be bindable, the method looks through the fields array to see if that element has data for in the specified data field. If so, it binds. If not... there's not much it can do (though ideally you would throw an exception). One thing to note about this is that it replicates the element and binds the text as a child. This is seen by the following line:

var bindableObj = obj.childNodes[e].cloneNode(false);

When you clone a node, you can say true, which means to clone it's children, or you can say false, which means to clone only that particular element. In this case, we don't need the children as this is a text repeater and we are going to put our own text as a child. If we were to say true, we would have to go out of our way to remove the children.

If the element is not found to be bindable, it copies the element and it's children as can be seen as the cloneNode(true).

Third, after the data object is ready you have a duplicate of the original repeater, but now filled with data from the data source. This data object is then bound to the browser's DOM as a element immediately before the repeater template. After all data objects have been bound, the original repeater is removed. Thus, you replaced the repeater template with data bound controls and you're done.

Here is the final implementation of the BindTextRepeater method:

var DataBinder = {
    BindTextRepeater: function(obj, ds) {
        var fields = new Array( );
        for(var f in ds[0]) { fields.push(f); }
        
        for(var r in ds) {
            var outputObj = DOM.createElement('div');

            if(ds[r]) {
                var d = ds[r]
                for(var e in obj.childNodes) {
                    if(obj.childNodes[e].nodeType && obj.childNodes[e].nodeType == 1) {
                        if(obj.childNodes[e].id && obj.childNodes[e].className && obj.childNodes[e].className.substring(0, 4) == 'bind') {
                            for(var i in fields) {
                                if(obj.childNodes[e].id == fields[i]) {
                                    var bindableObj = obj.childNodes[e].cloneNode(false);
                                    bindableObj.appendChild(DOM.createTextNode(d[fields[i]]));
                                    outputObj.appendChild(bindableObj);
                                }
                            }
                        }
                        else {
                            outputObj.appendChild(obj.childNodes[e].cloneNode(true));
                        }
                    }
                }
            }
            obj.parentNode.insertBefore(outputObj, obj);
        }

        obj.parentNode.removeChild(obj);
    }
};

Using this same approach of templating XHTML elements and reflecting JavaScript JSON data sources, you could actually create a full scale data binding solution for all your client-side data binding needs. Furthermore, since we used a JSON data source we can now bind data directly from JSON services accessed via Ajax techniques. Lastly, as I hope you can see, there wasn't really much magic in this example and absolutely no proprietary technology. It's simply a usage of what we already have and have had for many, many years.

Links

Converting JSON to XAML

For reasons beyond human comprehension, the world felt like making an huge deal about Microsoft "revealing" SilverLight even even though WPF/E has been known about for some time now and even though nothing technical has changed even in the slightest with the simple change of a name. Having said that... it will probably be an awesome technology and I'm sure I'll be marinating many of my future applications in it. Editing XAML in notepad is much more appealing to me than being forced to use the overpriced and overly complicated Flash.

As cool as that is, however, since most of the work I do involves pure Ajax/JavaScript clients with almost all .NET coding at the service level, I definitely find JSON (which IS a JavaScript object) easier to manage than XML (which CAN BE a JavaScript object). So, in one of my applications I have the service that provides graphical information to Silverlight in the form of JSON serialized XAML, which will then be converted into XAML.

Here is an example of something the service would provide:

var jsonElement1 = {
        'Ellipse': {
        'Canvas.Left': '130',
        'Canvas.Top': '130',
        Height: '200',
        Width: '200',
        Stroke: 'Red',
        StrokeThickness: '10',
        Fill: 'SlateBlue'
    }
};

No, it's not human readable like XML is, but it's what JavaScript loves to see and it's what my service creates. Also, no, this is done for for efficiently purposes. This doesn't lower the service "message" size in the slightest, but it does however help to keep a consistence programming model across all my service calls. Furthermore, given that the data was in a database and not in XAML on the server, there's no real overhead. If, however, the data was in XAML on the server it would be a sign of pure stupidity for me to convert that to JSON and then back to XAML.

The parsing for something like this is actually really simple: just iterate through the JSON objects and arrays and creating an XML tree from it. As a reminder or reference, with regard to XML in a web browser, Firefox uses document.implementation.createDocument for XML while IE uses the MSXML2.DOMDocument COM object. Furthermore, Firefox is more strict in its usage of XML than the more familiar COM model that IE uses.

Here is an example of what I mean:

var doc = null;
if(DOM.implementation && DOM.implementation.createDocument) {
    doc = DOM.implementation.createDocument('', '', null);
    Xaml.ScanJSONElements(doc, data, doc);


    var xmlSerializer = new XMLSerializer( );
    return xmlSerializer.serializeToString(doc);
}
else {
    doc = new ActiveXObject("MSXML2.DOMDocument");
    Xaml.ScanJSONElements(doc, data, doc);
    return doc.xml;
}

As you look through the Xaml.js file provided, you will also see that Firefox is very explicit about it's namespaces, while the COM model figured you will take care of them. There's nothing wrong with either approach, it's just something you will want to be aware of if you ever create XML in JavaScript.

Links

Object Range Selection and Emulating Word 2007's Formatting Box

Say you're working on a text driven web application and you want to get the selected text in order to see what was selected. With JavaScript that's easy enough, but what if you wanted to know what strongly-typed text was selected in order to recreate the selection later? This would come in tremendously handy if you want to have text annotation capabilities in your application. But, why stop there? If you are going to do that, why not add a nice pop-up window over your selection to give easy access to appropriate toolbox options? That's exactly what Word 2007 gives you and you can do the same in your JavaScript applications.

Implementing these two things involves the following tasks: assign each word (or letter if you want really fine grained control) a container span with an id and then watch for hovering over an object. When an object is hovered over, start a timer counter for the time of the hover. If hovering ends, reset the timer. When a specified amount of hover time has elapsed, see if they is a selection and if the object currently hovered over is in the selection. If so, show the toolbox. The first word and he last word selected are saved in the browser's Selection object as the 'anchorNode' and 'focusNode' objects of the selection, respectively.

Here's the meat:

// Get all spans and iterate through them making sure each REALLY exists and
// making sure each as an id.
var b = document.getElementsByTagName('span');
for(var a in b) {
    if(b[a] && b[a].id) {
    
        // Only use those with an id starting with 'wid'.
        if(b[a].id.substring(0, 3) == 'wid') {
        
            // Set the event that is called at each interval.
            b[a].timercall = function(evt){
            
                // It there is a saved object (see onmouseover event below), 
                // then continue...
                if(gHoverObject) {
                
                    // Increment counter.  When there are 4 timer intervals, 
                    // then get the object information and show the hover box.
                    hoverCounter++;
                    if(hoverCounter > 3) {
                    
                        // Get the text selection
                        var selection = window.getSelection( );
                        
                        // Does the selection contain the object the cursor is currently over?
                        // false means that the object the cursor is over must be fully selected.
                        // That is, half the word being selected won't cut it.
                        if(selection && selection.containsNode(gHoverObject, false)) {
                        
                            // Save the first object id selected and the last object id selected
                            toolboxObj.start = selection.anchorNode.parentNode.id;
                            toolboxObj.end = selection.focusNode.parentNode.id;
                            toolboxObj.style.display = 'block';
                            toolboxObj.style.left = parseInt(gHoverObject.x) + 'px';
                            toolboxObj.style.top = parseInt(gHoverObject.y) + 'px';
                        }
                    }
                }
            };

            b[a].onmouseover = function(evt) {
                // When the object is hovered over, save the object.
                gHoverObject = this;
                gHoverObject.x = evt.pageX;
                gHoverObject.y = evt.pageY;
                
                this.timer = setInterval(this.timercall, 150);
                hoverCounter = 0;
            };
            
            b[a].onmouseout = function(evt) {
                // Destroy the object so the algorithm doesn't run.
                gHoverObject = null;
                clearInterval(this.timer);
                hoverCounter = 0;
            };
        }
    }
}

The provided proof-of-concept demonstration also demonstrates how to setup regular text to be strongly typed. This is simply done by splitting the text by a space and putting each word into a span, then putting each span into a parent object and finally putting that parent object before the original text and deleting the original text. You can view all this happening and see the resulting structure using Firebug for Mozilla Firefox.

The proof-of-concept demonstration provided is for Mozilla Firefox only.  Internet Explorer does NOT have the abilities to do this.

Important Disclaimer: it's not my intention to teach anyone JavaScript. This information is not for someone to simply copy/paste into their own applications. A solid understanding of the DOM, JavaScript syntax and dynamics, and XHTML is required before any true application can be built. So, please do not ask me any "how do I..." questions. When I get those I merely explain the basics and tell the person to figure it out on their own. In other words, I won't do your homework for you.

Links

XmlHttp Service Interop - Part 2 (Utilizing WCF)

Today I'm publishing the second in an article series regarding XmlHttp Service Interop. In this article, entitled "Utilizing WCF", I explain how to build WCF services, how to trace their XML messages, and how to communicate with them and other SOAP services via raw XmlHttp.

Instead of posting the entire thing on my blog, from here on out I'm going to be posting articles in their own pages to make them easier to read and easier to access. This will also make it easier for me to update and edit as well. You may access this article as well as others in the series by the links below.

.NET Slides

Back in 2005 I taught a class where I gave an overview of various parts of the .NET universe (at the time, the WinFX universe). I covered everything from C# to data binding to ASP.NET to service-oriented architecture to web standards. My goal was to give a familiarization with each of the topics so that the students can then learn the topics on their own in a way that best fits them.

My first session, however, was a presentation experiment. Instead of using really nasty verbose slides, I had just a few words on a slide and on one slide I had simply the number 42. Don Box would have loved my presentation. The point of the experiment was to make sure that people were paying attention to the topic and not simply reading a useless slide. I really think that PowerPoint is a massive hindrance to education. You can access my experimental presentation, named .NET Overview, below.

My next to last session was on web standards and in this session I simply told a story and then gave a few examples showing how web standards development is the only web development that is acceptable. You can access this presentation, named Web Standards Presentation, below.

Below is also a link to a video where Don Box talks about giving great technical presentations. I would recommend this video to anyone who gives talks on really any topic. Don't just watch it, study it. It takes practice.