Markup extensions in AJAX

When we talked about bindings, we mentioned that the declarative approach relies on markup extensions. Today we’ll talk a little more about this feature. Markup extensions are expressions which are parsed and interpreted during the init event of the Sys.Application object. As we’ve seen, these expressions are delimited by{ and } and are always identified by a name For instance, bindings extensions are always identified by the *binding* name. Let’s recover one of the examples we’ve see when we talked about bindings:

<body xmlns:sys="javascript:Sys">
    <input type="text" id="source"
        value="Hi from bindings world!" />
    <input type="text" id="target"
        sys:value="{binding value, source=source, mode=twoWay}" />
</body>

The first name (*binding*) defined within the { } expression identifies the extension. The name is important because it lets the library know how to process it. Typically, these expressions have a list of properties composed by several entries of pairs key/value. There’s one exception: you’re allowed to specify a single entry to set the default property (this will make sense in a minute). In other words, the *value* entry you see in the previous property list of the binding expressions is the value of a special default property.

All markup extensions must be registered through the Sys.Application.registerMarkupExtension method. For instance, the binding extension we’ve been using until now is registered through the following method invocation:

Sys.Application.registerMarkupExtension(
  "binding",
  function(component, targetProperty, templateContext,properties) {
//code
},
false );

The markup extension registration process consists of identifying its name (first parameter), passing a reference to a function which will handle the values defined on the markup expression (second parameter) and specifying if the markup expression should be considered an expression. The function passed to the second parameter is responsible for transforming the markup extension into a JavaScript object. It expects several parameters:

  • component: references the component that contained the current markup expression;
  • targetProperty: identifies the name of the property (ie, the attribute) where the current expression was defined;
  • templateContext: context of type Sys.UI.TemplateContext used during the current processing (this is used when you use templates – more about templates in future posts);
  • properties: literal JavaScript object. The properties of this object match the values defined on the expression property list. The default value is saved on a property named $default.

Lets pay attention to the binding markup extension processing function:

function(component, targetProperty, templateContext, properties) {
    var binding = new Sys.Binding();
    binding.set_source(templateContext.dataItem);
    binding.set_templateContext(templateContext);
    binding.set_target(component);
    binding.set_targetProperty(targetProperty);
    for (var p in properties) {
        if (properties.hasOwnProperty(p)) {
            var value = properties[p], isString = (typeof(value) === "string");
            switch (p) {
                case "$default":
                    binding.set_path(value);
                    break;
                case "mode":
                    Sys.Observer.setValue(binding, p, isString ? Sys.BindingMode.parse(value) : value);
                    break;
                case "ignoreErrors":
                    Sys.Observer.setValue(binding, p, isString ? Boolean.parse(value) : value);
                    break;
                default:
                    Sys.Observer.setValue(binding, p, value);
                    var setter = binding["set_" + p];
                    setter ? setter.call(binding, value) : binding[p] = value;
                    break;
            }
        }
    }
    templateContext.components.push(binding);
    binding.initialize();
}

As you can see, there’s not much work going on here. The default property($default) is always passed into the path property of the binding. Another interesting thing you’ve probably noticed is that component and targetProperty are used to set the  target and targetProperty properties of the Sys.Binding object.

Even though the current release only introduces the binding and ref markup extensions (btw, both of them end up building Sys.Binding objects), nothing prevents you from creating your own markup extensions. You just need to register them and build the function which will end up doing the real work.

And that’s it for now. Stay tuned for more on MS AJAX.

Advertisements

~ by Luis Abreu on October 12, 2009.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: