Using the power of binding to animate changes

In a recent post, I showed how the binding component can be instantiated independently of the {binding} markup extension. But there’s a whole lot more it can do.

For instance, it has two very interesting callback properties, convert and convertBack that get called any time the binding sees a change respectively on the source or on the target of the binding. The original purpose of those functions is to handle the back and forth conversion of data.

For example, if you’re binding an input tag’s value property to a column of type Date, you’ll want to set convert to a function that formats the date according to the current culture, and convertBack to a function that parses it back from string form to date form.

But this couple of functions can also be used as change event handlers of sorts and even if we have no conversion to do, we can still use them to trigger some side effects, such as an animation. The functions get the value to convert and the binding as the parameters, and return the converted value. Here is a function that triggers an animation on the target of the binding and then returns the unchanged value that got passed in:

function flashTarget(value, binding) {
    var target = binding.get_target();
    if (target.nodeType == 3) {
        target = target.parentNode;
    }
    $(target)
        .jFade({
            property: 'background',
            start: 'FFFF00',
            end: 'FFFFFF',
            steps: 25,
            duration: 30
        });
    return value;
}

The function first gets the target element from the binding component. Then it looks at the type of the target element because in the case of a text node you really want to animate its parent, not the text node itself. Then, we’re using jQuery and the jFade plug-in to animate the element. And finally, of course, we return value unchanged.

Adding the binding animation is as simple as specifying a convert or convertBack function on each binding, for example:

<span>{binding answer, convert=flashTarget}</span>

Here’s the complete code for the sample page:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Binding</title>
    <script type="text/javascript">
        var data = {
question: "Life, the universe and everything",
answer: 42
}; function flashTarget(value, binding) { var target = binding.get_target(); if (target.nodeType == 3) { target = target.parentNode; } $(target) .jFade({ property: 'background', start: 'FFFF00', end: 'FFFFFF', steps: 25, duration: 30 }); return value; } </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView" sys:activate="*"> <form id="form1" runat="server"> <asp:ScriptManager runat="server" ID="SM1"> <Scripts> <asp:ScriptReference Path="~/Script/MicrosoftAjaxTemplates.js" /> <asp:ScriptReference Path="~/Script/jquery-1.2.6.js" /> <asp:ScriptReference Path="~/Script/jquery.jfade.1.0.js" /> </Scripts> </asp:ScriptManager> <div sys:attach="dataview" dataview:data="{{ data }}"> <span id="questionDisplay">{binding question,
convert=flashTarget}</span><br /> <input type="text" id="question" value="{binding question, convertBack=flashTarget}"/><br /> <span id="answerDisplay">{binding answer,
convert=flashTarget}</span><br /> <input type="text" id="answer" value="{binding answer, convertBack=flashTarget}"/> </div> </form> </body> </html>

The page contains two input boxes and two labels that reflect the same values that are in the input boxes. Any time the text in one of the boxes is changed, both the box and the label that’s bound to the same data will flash yellow then fade back into white:Elements flashing yellow on change.

Cool, uh?

4 Comments

  • Le Roy,

    I managed to get the jQuery DatePicker to work with MS Ajax Templates by using the DatePicker in Dialog mode so that I can bind to its datechange event and shove that date back into a Javascript Object property.

    Now I find myself trying to figure out how to do a combobox. I can effectively bind the check to it one way, but it does not work both ways. Do I have to utilize ConvertFrom to accomplish this, or is there some simple way I am not thinking about?

    Ex:



    This will effectively show it checked or not checked if datasource.PropertyName is true of false, but checking and unchecking the box does not seem to have an effect.

  • Corey -- two problems. (1) you should have type="checkbox" not 'check' which isn't right. (2) you need to use sys:checked instead of checked. For example, . The reason is that IE does not actually allow 'any' value to be in certain attributes such as checked (selected, ismap, readonly, to name a few others). Programmatically all you get back is 'true' or 'false'. So there's no way for us to notice the binding text in the markup. For this reason we allow any attribute to be prefixed with sys, which also helps you avoid any side effects the normal attribute would have. For example, if you put the browser would actually try to request a "{binding..}" url from the server.

  • That worked perfectly InfinitesLoop! Now am I also missing how you can bind an array to a select box?

    I.e.


    If there is a javascript object
    var someArray = [{
    Text: "something",
    Value: "somethingValue"
    }, ...]

  • @Corey: I think the readme says binding select is a known issue. For the moment you'd have to create a control. I think there's on in the old Futures release from last year that may still work.

Comments have been disabled for this content.