LA.NET [EN]

JavascriptArchive

Oct 30

Getting started with the DataContext object

Posted in Javascript, MS AJAX       Comments Off on Getting started with the DataContext object

Yesterday, I’ve started looking at the DataContext object. I haven’t still tested all its features (to do that, I still need to take a look at ADO.NET Data Services and study the AdoNetDataContext type), but I’ve already picked up some ideas about it.

I guess it’s fair to say that you can think of the DataContext as a buffer which keeps track of the changes  you do along the time. Besides tracking basic changes, it does also support several more advanced concepts like links (which are just “fancy relations” between different objects – I think that most of this stuff is there to support interactions with the ADO.NET Data Services).

Since this is just an intro post, we’ll only be looking at its basic features. Creating a new DataContext instance can be easily accomplished through the Sys.create object helper:

<script type="text/javascript">
  var items = [
    { name: "luis", address: "fx" },
    { name: "john", address: "fx" },
    { name: "peter", address: "fx" }
  ];
  var _ctx = null;
  Sys.require([Sys.components.dataContext])
  Sys.onReady(function () {
    _ctx = Sys.create.dataContext();
});
</script>

Once again, we rely on the script loader for getting the necessary JavaScript files and populating the helper objects with new methods (ex.: Sys.create.dataContext). The previous DataContext instance is “empty”. However,I’m positive that in most scenarios you’re really interested in populating it with some data that will be tracked over time. The DataContext lets you do that through trackData method:

_ctx.trackData(items);

If you’ve looked at the DataContext’s prototype object,then you might think that calling trackData ends up initializing the items property. However, that will only happen if the DataContext object has been previously configured with identity related methods (we’ll be talking about this feature in future posts). Since we’re not using these advanced features, we’ll end up getting the data saved in the _lastResults property:

datacontext1

Now that the DataContext has been “initialized” with data, we can use it to, say, add a new item to that internal array:

_ctx.insertEntity({ name: "charles", address: "lx" });

You won’t be surprised by knowing that the previous line ends up “adding” a new item to the list of objects tracked by the _ctx DataContext instance. However, the new item won’t be added to the _lastResults array; instead, it gets added to the private _inserts property:

datacontext2

I’ve expanded the _lastResults, _items and _inserts fields of the _ctx instance. As you can see, _lastResults remains unchanged. The inserted item is appended to the _inserts array and you’ll also get a new entry on the _changeslist property. Even though I’m mentioning the _lastResults and _inserts fields, the truth is that you shouldn’t use them in your code (they’re considered private details and should only be managed by the DataContext instance). You can, however, get a reference to the _changeslist field through the get_changes public property:

var changes = _ctx.get_changes();

The local variable changes is just a collection of Sys.Data.ChangeOperation instances, which expose the following properties:

  • action: value from the Sys.Data.ChangeOperation enumeration (insert, update or remove) which identifies the current entry;
  • item: reference to the item of the operation (when adding, editing or removing items from the data context, this property references the object which was used in the operation);
  • linkSource: used for identifying the source of a link operation;
  • linkSourceField: identifies the field of the linkSource object used in the link operation;
  • linkTarget: identifies the target object used in a link operation.

The last three properties displayed in the previous list are only used for link operations (which we’ll talk about in future posts).

Since changes is an array, we can print all the changes by using a simple for loop. Notice that this will only show changes which haven’t been “persisted” by the DataContext instance (more about this topic at the end of this post):

for (var i = 0; i < changes.length; i++) {
  alert(changes[i].action + "-" +
                changes[i].item.name + "-" +
                changes[i].linkSource + "-" +
                changes[i].linkTarget + "-" +
                changes[i].linkSourceField);
}

To wrap up the data context’s insertEntity method topic, I’d like to add two things:

  • currently, the method expects two parameters: the first, is a reference to the entity that you’re adding to the current context; the second, is supposed to be a string which identifies the entity set to which this element belongs (this will be used when the DataContext instance has been customized to support identities – since we’re not using those features, we didn’t pass anything for this second parameter);
  • all the insertion operations need to go through the insertEntity method… and this is also true for observable arrays (in other words, if you’re thinking that you can add new items to an observable array which has been associated with a DataContext through the use the “observable array methods” and still have those changes recorded by the DataContext, then forget it).

Now that we’ve seen how insertion works, it’s time to see how we can remove items from the DataContext instance. In this case, we must use the removeEntity method:

_ctx.removeEntity(items[0]);

Removing an item ends up adding a new ChangeOperation to the internal _changelist field. If you run the previous for loop, you’ll see that it has two changes: one for the insertion and another one for the removal of the item. And yes, the private _deletes array will end up with one entry (which references the element that has been removed).

Now, lets make things a little more interesting…Take a look at the following snippet:

var aux = { name: "charles", address: "lx" };
_ctx.insertEntity(aux);
_ctx.removeEntity(aux);

What do you expect to happen now? If you’re thinking that you’ll end up with _insert and _delete empty arrays and with no changes (ie, with an empty _changeslist array), then you’re absolutely right. That happens because you’ve inserted and removed the same item without “committing” the insertion. The next image shows these results:

datacontext3

From the three basic operations, we’re only missing one: editing an item. To understand editing, we need to go back and talk a little more about tracking data. Besides initializing the _lastResults field, the trackData ends up hooking all the array items’ property changed events so that the DataContext instance is notified of any change made to any of the objects that it’s tracking.

In practice, this means that you’ll need to use the observable methods to change an item that is being tracked by a DataContext instance. For instance, the next snippet changes the address of the first item that is being tracked:

Sys.Observer.setValue(items[0], "address", "pt");

Which produces the following internal changes in the DataContext instance:

datacontext4

Btw, do notice that in editing scenarios, the item ends up being modified (notice the _lastResult’s first item address). As you might expect, the edit operation ended up leading to new entries in the private _changelist and _edits fields too.

Notice that if you’re updating an item which was added after the DataContext has started tracking data, then that edit operation will be performed, but it won’t be registered in the _changeslist collection (because there’s still a pending insert operation which, when performed in the back office, ends up doing everything  with a single insertion instruction).

And I guess this covers the basic operations related with inserting, editing and removing items that are being tracked by a DataContext object. In the next posts, we’ll keep looking at this object. Stay tuned for more in MS AJAX.

Oct 29

DataViews, DataViews and more DataViews: DataViews everywhere!

Posted in Javascript, MS AJAX       Comments Off on DataViews, DataViews and more DataViews: DataViews everywhere!

Ok, I think this title might have caught your attention! (at least, that’s what I’m hopping for!). This post is a direct consequence of another discussion with a friend regarding the use of the DataView control. He told me something like this: “well, DataViews are cool…can’t deny it…but it’s only for listing items and that means it’s only usable for grids…”

Aha! That is not correct. And to show him that he was wrong, we’ve settled in a challenge (not as interesting as top gear’s challenges, but still…). After some discussion, we’ve settle in simple scenario: an edit form for a complex JavaScript object. Here’s the UI:

complexform

The print button you see is there to give feedback on the values of the properties of the person object. And here’s the JavaScript for the objects used in the sample:

var contactTypes = [
      { id: 1, description: "phone" },
      { id: 2, description: "email"}];
var person = {
  name: "luis",
  address: "some place",
  contacts: [
    { contact: "123123123",type: contactTypes[0]},{ contact: "labreu@somewhere.pt", type: contactTypes[1]}
  ]
};

As you can see, we’ve got a collection of literal contact types objects which are used for identifying the types of each of the contacts saved in the person object.  To solve this problem, I’ve ended up defining three DataView controls:

  • one for the top form;
  • another for listing the contacts;
  • another one for populating the SELECT control used for presenting the type of contact (we can all agree that this is not a grid, right?:) ).

Here’s the final markup I’ve ended up using:

<div id="mainView"
     class="sys-template"
     sys:attach="dv"
     dv:data="{{person}}">
     <label for="name">Name:</label>
     <input type="text" name="name" 
sys:value="{binding name}" /> <br /> <label for="name">Address:</label> <input type="text" name="name"
sys:value="{binding address}" /> <table> <thead> <tr> <td>Contact</td> <td>type</td> </tr> </thead> <tbody sys:attach="dv" class="sys-template" dv:data="{binding contacts}"> <tr> <td> <input type="text"
sys:value="{binding contact}" /> </td> <td> <select id="contactTypes" sys:attach="dv" class="sys-template" sys:value=
"{binding type, convert=getId, convertBack= getContactType}" dv:data="{{ contactTypes }}"> <option sys:value="{{id}}">
{{description}}
</option> </select> </td> </tr> </tbody> </table> </div> <input type="button" value="print info" id="print" />

There are a couple of interesting things going on here:

  • the top DataView control is used for allowing me to use templates (which rely on bindings) for filling the form automatically and setting the context for the inner DataView controls;
  • the second DataView control displays a grid which shows the contacts for the current person. As you can see, it’s really similar to what” we’ve used before.
  • the third DataView is applied…to a SELECT element. We need to fill the select with the available contact type options and the easiest way to do that is to simply associate it with a DataView control and set its data to the contactTypes object. However, we need to select the correct type for the “current” contact and that’s where the sys:value enters the scene.

Btw, we do need to define two convert functions for ensuring proper setting of each of objects that participate in the binding relationship. Here’s the code for those functions:

Sys.converters.getId = function (value, binding) {
  return value.id;
};
Sys.converters.getContactType = function (val, binding) {
  for (var i = 0; i < contactTypes.length; i++) {
    if (contactTypes[i].id == val) {
      return contactTypes[i];
    }
  }
  //probably should throw here?
  return null;
};

The getId conversion function is invoked when the value is being propagated from the person’s contact object to the dropdown. In this case, we only need the ID in order to select the correct OPTION; on the other hand, when the value is being propagated from the dropdown to the “current” contact, we do need to convert the OPTION’s value into an object (and that’s why we’re using a for loop in the getContactType method). Btw, here’s another picture which shows that alterations are in fact propagated back to the object:

complex2

Even though I’m not showing the code for print button, I can assure you that it’s the longest method of this demo page. As you can see, the DataView is really a useful control. Combining it with templates and bindings does really cut down the code needed for several real world scenarios.

And that’s it for now. Stay tuned for more!

Oct 29

DataView and remote web service invocation: adapting the data returned from the server

Posted in Javascript, MS AJAX       Comments Off on DataView and remote web service invocation: adapting the data returned from the server

Yesterday I’ve ended up receiving an interesting question regarding the code I’ve used in the posts which explain how to get data from a remote web service. The question was: how do we adapt the data returned from the web service before it is used by the DataView for rendering its HTML?

This is an interesting question. Fortunately, the answer is not really complicated. To illustrate this problem and its solution, we’ll start by going back to  the Person class we’ve introduced in the server side:

[DataContract]
public class Person {
    [DataMember(Name="name")]
    public String Name { get; set; }
    [DataMember(Name="address")]
    public String Address { get; set; }
}

As you can see, we’re using the DataMemberAttribute for influencing the name of the properties used in the JavaScript objects that will be returned from the service. Now, let’s assume that we don’t own the service and that the Person class looks like this:

[DataContract]
public class Person {
    [DataMember()]
    public String Name { get; set; }
    [DataMember()]
    public String Address { get; set; }
}

Now the problem: we want to adapt the data received from the server so that we don’t have to change the template used by the view. Btw, here’s how the template is currently defined:

 <tr>
    <td>{{name}}</td>
    <td>{{address}}</td>
  </tr>

If we leave the code as is, we’ll end up getting errors because *now* each JavaScript Person instance has two properties named Name and Address (instead of name and address). Ok, I guess you could say that it’s a lot easier to just update the names of the properties used in the templates than to change the data; however, changing the data gives me the chance to introduce another technique which might be useful for you in other less contrived scenarios…

When I thought about intercepting and changing the data, I thought that the fetchSucceeded event would be a good place to do that. Unfortunately, this event is only fired after the DataView control has refreshed itself: by then, you’d already received an exception saying that name is undefined!

Ok,time to go back to the prototype definition of the control…and to read a previous post on the topic of DataView events. And yes,the answer to our problem is right there, on the first event described on this post:

rendering: this event is generated when the DataView control is about to start instantiating its template to get the rendered HTML. Any function which handles this event receives two parameters: the first, references the DataView control which generated the event; the second is an instance of the Sys.Data.DataEventArgs type;

Hooking up the rendering event is all we need to adapt the data. here’s some code that adapts the JavaScript objects returned by the server (as you can see, we’re replacing each instance with a new one that has the correct names):

function updateData(sender, e) {
  var data = e.get_data();
  for (var i = 0; i < data.length; i++) {
    data[i] = { name: data[i].Name, 
address: data[i].Address } } }

Since we’re using a declarative approach, hooking up the event can be done by using the on rendering attribute:

dv:onrendering="{{ updateData }}"

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

Oct 28

In the previous posts, we’ve seen how to configure the DataView control so that it gets the data from a remote web service. In this post, we’ll see how we can take advantage of the fetchParameters to pass info to the web service. The idea is simple: we’ll update the previous sample so that it renders a table with clickable headers used for sorting the displayed data. Sorting the data will be done on the server. This means we need to start updating the server side code so that the web service method gets the info used for sorting (notice I’m only showing the changes made to the initial code):

public class PeopleService {
    static List<Person> _people = new List<Person>
        {
            new Person{ Name = "luis", Address = "fx"},
            new Person{ Name = "john", Address = "lx"},
            new Person{ Name = "peter", Address = "pt"}
        };
    [OperationContract]
    [WebGet]
    public IEnumerable<Person> GetPeople(SortOrder sort) {
        var ordered = _people.OrderBy( 
p => (sort == SortOrder.Name ?
p.Name : p.Address) ); return ordered; } } public enum SortOrder { Name, Address }

As you can see, changes are really minimal: we’ve added an enumeration used for indicating the sort order that should be applied to the collection and we’ve updated the GetPeople method so that it orders the collection accordingly. Now, let’s see the client code:

<head runat="server">
  <title></title>
  <style type="text/css">
      .sys-template{
          display: none;
      }
  </style>
  <script src="Scripts/MicrosoftAjax/start.debug.js" 
type="text/javascript">
</
script> <script type="text/javascript"> Sys.require([Sys.scripts.jQuery, Sys.scripts.WebServices,Sys.components.dataView],function () { Sys.loadScripts(
[
"PeopleService.svc/jsdebug"], function () { Sys.Application.activateElement(
Sys.get("#view")); $("thead td").click(function () { var view = Sys.get("$view"); view.get_fetchParameters()
.
sort =
(
$(this).text() === "Name" ?
SortOrder.Name :
SortOrder.Address); view.fetchData(); }) }); }); </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dv="javascript:Sys.UI.DataView"> <table> <thead> <tr> <td>Name</td> <td>Address</td> </tr> </thead> <tbody id="view" class="sys-template" sys:attach="dv" dv:autofetch="true" dv:httpverb="GET" dv:dataprovider="{{ PeopleService }}" dv:fetchoperation="GetPeople" dv:fetchparameters="{{ { sort: SortOrder.Name } }}"> <tr> <td>{{name}}</td> <td>{{address}}</td> </tr> </tbody> </table> </body>

 

Most of the code is similar to what we had before. There are, however, some differences:

  • I’ve added JQuery to set a click handler to all the TD elements of the header (I still love jQuery 🙂 );
  • we’ve attached the DataView control to the tbody element of the table. This is the easiest way to define the templates without ending up with crappy HTML (thanks go once again to Dave Reed for pointing me in the right direction);
  • in response to a click event on one of the header TDs, we set the sort parameter to the correct value. In a real world app, I’d check that the user was really asking for a different sorting before starting the remote call which refreshes the control (after all, if the data is already ordered by Name, there really isn’t any need to reorder it again by name, right?);
  • after setting everything up, we refresh the data presented by the control by calling the fetchData method. This method will perform the remote call and will automatically refresh the DataView control with the new sorted data.

And there you go: quick and easy, right? Stay tuned for more on MS AJAX.

Oct 28

Feeding the DataView control with data returned from a Web Service – take II

Posted in Javascript, MS AJAX       Comments Off on Feeding the DataView control with data returned from a Web Service – take II

In the previous post, we’ve seen how we can configure the DataView control to get data returned from a web service. The previous approach is a good one if you don’t intend to use a proxy to a web service. However, suppose you’ve already have a web service proxy and that you want to reuse it for getting the data that is needed by the DataView…in that case, the best option might be reusing that proxy.

To show you the necessary steps for configuring the DataView control to do that, we’ll reuse the previous server side code and we’ll only update the client side:

<head runat="server">
  <title></title>
  <style type="text/css">
      .sys-template{
          display: none;
      }
  </style>
  <script src="Scripts/MicrosoftAjax/start.debug.js" 
type="text/javascript">
</
script> <script type="text/javascript"> Sys.require([Sys.scripts.WebServices, Sys.components.dataView], function () { Sys.loadScripts(["PeopleService.svc/jsdebug"], function () { Sys.Application.activateElement(
Sys.get("#view")); }); }); </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dv="javascript:Sys.UI.DataView"> <div id="view" class="sys-template" sys:attach="dv" dv:autofetch="true" dv:httpverb="GET" dv:dataprovider="{{ PeopleService }}" dv:fetchoperation="GetPeople"> <div> <span>{{name}}</span>- <span>{{address}}</span> </div> </div> </body>

Ok, so there’s lot of things going on here:

  • We start by indicating the required dependencies (similar to what we had in the previous post). Since we want to use a web service proxy, we need to add a new script node which references the “special” url PeopleService.svc/jsdebug (notice that I’ve got the page and the service in the same folder). However, we can only do that after the base classes used by the proxy have been defined and injected in the page (that’s why we’ve passed an anonymous function which will be called when all the base dependencies are loaded);
  • nothing prevents you from adding the script nodes “by hand”. However, you should keep in mind that the Sys.loadScripts method exists and contains all the code needed for adding the new script node and hooking up the ready event so that you get notified when the script has been loaded;
  • unfortunately,loading a new script from within the first callback function (the one that was passed for the Sys.require method) stops future processing of the normal notifications of the page. In other words,you will not get any Sys.onReady or pageLoad calls. And that’s why we need to activate the DataView control “by hand”. Fortunately, we can rely on a simple method call for kicking off that work (notice the Sys.Application.activateElement call). Btw, if you had several controls, you could easily activate them all by passing a reference to the document element (document.documentElement). And yes, we’re activating the pages from within a callback that will get called adter the web service proxy code has been loaded and processed;
  • the only noticeable thing in the markup is the DataView’s dataProvider definition: we used a one-time/one-way binding to set it to the web service proxy which was added to the page through the previous Sys.loadScripts call.

And I guess this sums it up quite nicely. But there’s still lots of things to talk about so stay tuned for more on MS AJAX.

Oct 28

Until now, we’ve been using static data to feed all the DataView controls we’ve been using in the MS AJAX series. Today we’ll see how we can configure the control so that it automatically gets data returned from a web service call. To get things started, we’ll start by introducing the server side code for the WCF service:

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(
RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)] public class PeopleService { [OperationContract] [WebGet] public IEnumerable<Person> GetPeople() { var people = new List<Person> { new Person{ Name = "luis", Address = "fx"}, new Person{ Name = "john", Address = "lx"}, new Person{ Name = "peter", Address = "pt"} }; return people; } } [DataContract] public class Person { [DataMember(Name="name")] public String Name { get; set; } [DataMember(Name="address")] public String Address { get; set; } }

Yes, not the best code in the world, but don’t forget that I’m not interested in creating web service! What I want is to show you how to properly configure the DataView control to get data from a web service…

As you can see, PeopleService is a WCF service which has a single operation: GetPeople. This method returns a collection of Person instances (since I wanted to preserve JS naming conventions, I’ve used the DataMemberAttribute to customize the name of the properties used in JSON returned from the server).

And now we can proceed with the most important part: configuring the DataView for getting the data automatically from the server side. In this case,I’ve opted for using the declarative approach:

<head runat="server">
    <title></title>
  <script src="Scripts/MicrosoftAjax/start.debug.js" 
type="text/javascript">
</
script> <script type="text/javascript"> Sys.require([Sys.scripts.WebService,
Sys.components.dataView]); </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dv="javascript:Sys.UI.DataView"> <div id="view" class="sys-template" sys:attach="dv" dv:autofetch="true" dv:httpverb="GET" dv:dataprovider="PeopleService.svc" dv:fetchoperation="GetPeople"> <div> <span>{{name}}</span>- <span>{{address}}</span> </div> </div>

We start by loading the JS files needed for communicating with the server and using the DataView control. Since we need to communicate with the server side through a remote web service method call, we need to get the base classes defined in the MicrosoftAjaxWebService.js file.

Configuring the DataView isn’t really hard since we only need to set a couple of properties:

  • autofetch: this property expects a Boolean. Setting it to true makes the DataView control fetch the data from the web service automatically during its initialization;
  • httpverb: you can use this property to set the type of HTTP method call which will be used for communicating with the server;
  • dataprovider: this property is used for setting the provider which will return the info that populates the DataView control. You can pass one of the following types to it: a reference to an object which implements the Sys.Data.IDataProvider interface (ex.: a DataContext object), a reference to a web service proxy or a string with the URI of the service. In this example, I’ve opted for using a string which identifies the URI of the web service (we’ll leave the other options for future posts);
  • fetchOperation: the name of the operation which returns the data. You’ll typically use this property when you pass a web service proxy to the DataView’s dataProvider property. In the previous snippet, I’ve opted for using it to set the name of the method (notice that this wasn’t really needed because I could have initialized the DataView’s dataProvider property with the complete path to the web service method – ie, “PeopleService.svc/GetPeople”).

Besides these properties, there are a still a couple of properties related with getting data from a remote provider:

  • fetchParameters: literal object with the parameters that should be passed for the remote service method;
  • timeout: you can use this property to set the timeout in milliseconds;
  • isFetching: read-only property which indicates if the control is performing a remote call for fetching the data;

When the DataView control is fetching data from a remote provider, you can abort that operation by invoking the abortFetch method. On the other hand, you can force a remote call by invoking the fetchData method. Calling this method starts a remote call and will automatically refresh the control with the new data that is returned from the provider.

Besides properties and methods, the control has a couple of events which you can handle:

  • fetchFailed: this event will be generated when the remote call fails;
  • fetchSucceeded: as you can probably guess, this event will be fired when the DataView control receives a successful response from the provider.

A fetchfailed handler receives three parameters:

  • a reference to the error returned from the server;
  • a custom user context object which might have been passed to the control;
  • a string (“fetchData”) which identifies the method that originated the handle call;

A fetchSucceeded handler also expects the same number of parameters as the ones that are passed to the fetchFailed handler: the main difference is that the first parameter references the data returned from the service.

And this should be enough for getting you started with getting data through remote calls. There’s still more to come, so stay tuned!

Oct 27

In these last posts, we’ve already met several of the events generated by the DataView control. I thought it would be a good idea to write a small post which documents many of the events we’ve seen in the past:

command: fired when a user clicks over an element which has been “marked” with the sys:command system attribute;

  • rendering: this event is generated when the DataView control is about to start instantiating its template to get the rendered HTML. Any function which handles this event receives two parameters: the first, references the DataView control which generated the event; the second is an instance of the Sys.Data.DataEventArgs type.;
  • rendered: marks the end of the HTML rendering process. Functions configured as handlers receive two parameters: the first, references the DataView which generated the event; the second, is an instance of the Sys.DataDataEventArgs type;
  • itemRendering: event that is generated before each item’s template instantiation. We can do several interesting things here, like changing the default template or influencing the data that is going to be used during the template instantiation;
  • itemRendered: event which signals the end of the instantiation of a template. We’ve seen how we can use this event to customize the generated HTML for an item.

The Sys.Data.DataEventArgs object used by the rendering and rendered events introduces some interesting properties:

  • data: references the items that will be used for instantiating the templates;
  • itemPlaceholder: used for identifying the place holder where the template’s generated HTML will be put;
  • itemTemplate: reference to the template used for instantiating all the elements.

During the rendering event, you can set all of these properties  and influence the HTML generated by the DataView control.

Besides these events, there are still others, but we’ll leave them for the next posts because they’re related with the integration of the DataView control with data contexts. Stay tuned for more on MS AJAX.

Oct 26

In one of the previous posts of the series, we’ve seen how easy it is to build a master-detail scenario with the help of the new DataView control. Today, we’ll keep looking at it and we’ll see how we can build an editable grid. The next two images explain the objective of our post. The first shows the grid in browse mode while the second illustrates what it looks like in edit mode:

browsemode

editmode

As you can see, the idea is simple: any row can be in editing or browsing mode (notice that we can only edit one row at the time). While in browsing mode, you can move it to edit mode or you can simply delete it. In edit mode, you can only confirm the changes or cancel them.

If you’ve been playing with the DataView control, then you’ll know that you’ll need two templates: one used for displaying the row in browse mode and another to display it in edit mode. Here’s the HTML I’ve used for the control and for each of the templates:

<body xmlns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
    <div id="view"
          sys:attach="dv"
          dv:data="{{items}}"
          dv:onitemrendering="{{handleItemRendering}}"
          dv:itemtemplate="#browse"
          dv:oncommand="{{handleCommand}}">
    </div>
    <div id="browse"
          class="sys-template">
        <div>
          <span>{{name}}</span> -
          <span>{{address}}</span>
          <a sys:command="edit" href="" 
sys:commandargument="{{$index}}"
onclick="return false;">Edit</a> <a sys:command="delete" href=""
sys:commandargument="{{$index}}"
onclick="return false;">Delete</a> </div> </div> <div id="edit" class="sys-template"> <div> <input type="text" id="name"
sys:value="{binding name, mode = oneWay}"/> <input type="text" id="address"
sys:value="{binding address, mode = oneWay}"/> <a sys:command="update"
sys:commandargument="{{$index}}" href=""
onclick="return false">Update</a> <a sys:command="cancel" href=""
onclick="return false">Cancel</a> </div> </div> </body>

In this case, I’ve opted for using two external templates: the first one uses spans for showing the name and address of each object + the anchors needed for raising edit and delete commands. The second one has some textboxes plus update and cancel “buttons”. By default, the DataView control uses the browsing template (notice the dv:itemtemplate=”#browse” attribute usage).

As you can see, we’re using commands for signaling the operations. We’re also relying on command arguments for getting the current position of the element that raises a command (the only command which doesn’t require knowing the position is the cancel command).

One thing that might have caught your attention is the use of one-way bindings between the INPUT controls and the objects. Unfortunately,that’s the only way to guarantee that the changes made in the textboxes won’t be propagated automatically to the associated objects (in other words,two way bindings won’t help here because they will automatically propagate all the changes to the associated objects and that means the cancel button wouldn’t really work).

Without further ado, lets take a look at the JavaScript:

<script type="text/javascript">
  var items = [
    { name: "luis", address: "fx" },
    { name: "john", address: "lx" },
    { name: "rita", address: "pt" }
  ];
  Sys.require([Sys.components.dataView],
  function () {
Sys.Observer.makeObservable(items); Sys.UI.DataView.prototype.editElement =
f
unction (pos, addingNewItem) { this.__editIndex = pos; this._isNewItem = addingNewItem; } Sys.UI.DataView.prototype.cancelEditElement =
fun
ction () { this.__editIndex = -1; this.__isNewItem = false; } }); function handleCommand(sender, e) { function delItem(sender, e) { items.removeAt(e.get_commandArgument()); } function updateItem(sender, e) { var name = sender.get_contexts()[ e.get_commandArgument()] .get("#name") .value; var address = sender.get_contexts()[ e.get_commandArgument()] .get("#address") .value; //probably do some validation here var item = items[e.get_commandArgument()]; item.name = name; item.address = address;
sender.cancelEditElement(); sender.refresh(); } function editItem(sender, e) { sender.editElement(e.get_commandArgument(), false); sender.refresh(); } function cancelItem(sender, e) { sender.cancelEditElement(); sender.refresh(); } switch (e.get_commandName()) { case "delete": delItem(sender, e); break; case "update": updateItem(sender, e); break; case "cancel": cancelItem(sender, e); break; case "edit": editItem(sender, e); break; default: return; } } function handleItemRendering(sender, e) { function find(item, arr) { for (var i = 0; i < arr.length; i++) { if (arr[i] === item) { return i; } } return -1; } if (sender.__editIndex === undefined || sender.__editIndex === -1 || find(e.get_dataItem(), items) !==
sen
der.__editIndex)
{
return; } e.set_itemTemplate("#edit"); } </script>

 

There are a couple of interesting things going on here:

  • we start by adding two new helper methods to the DataView’s prototype object: editElement and cancelEditElement. The first is used for setting the __editIndex property with the index of the row that should be placed into edit mode; the second method cancels an ongoing editing operation (by setting that property to –1);
  • most of the work happens in the handleCommand function. As  you can see, we’ve got a separated inner function for each command. This was not needed, but I guess it improves reading quite a bit;
  • the edit anchor doesn’t really do much: it will simply set the current edit index to the value it receives from the command argument;
  • cancelling is even simpler since it simply resets the current edit index;
  • removing an item is also simple because we’ve made items an observable array (and that means easy elimination and propagation of that info to the DataView control);
  • updating is the most complicated operation. We start by getting the values of the textboxes (by relying on the get helper method which is available from the current TemplateContext object). After that, we should probably run some sort of validation to ensure that the introduced values are correct. We’ve dismissed that step because this is only demo code. Since the textboxes weren’t bound to the object’s property, we need to update those properties “by hand”. That means we’ll need to use the command argument value to get the current index in order to get a reference to the item that is being edited;
  • several of the operations end up firing a refresh operation. This refresh is needed to ensure that the correct template is used;
  • We need to handle the itemRendering event because we might need to change the default template. When the “current item” is in edit mode, we change the template through the set_itemTemplate helper (as you can see, we needed to write some extra code because currently we can’t get the position of the current item from the event args parameter that is passed to the function).

And that’s it. With a little JS code, we’ve ended with a cool template which lets us add edit in place to a simple grid. We could improve the previous code for supporting new items, but I’ll leave that for you. And that’s it for now. Stay tuned for more on MS AJAX.

Oct 26

One of the cool features MS AJAX preview 6 introduces is better JQuery integration. From now on, MS AJAX components (which have been defined through a script info object registered through a defineScript(s) method call) are exposed as jQuery plugins. This means that you can write something like this:

<head runat="server">
  <style type="text/css">
      .sys-template{
          display:none;
      }
  </style>
  <script src="Scripts/MicrosoftAjax/start.debug.js" 
type="text/javascript">
</
script> <script type="text/javascript"> Sys.require([Sys.components.dataView,
Sys.scripts.jQuery]); var items = [ { name: "luis", address: "fx" }, { name: "john", address: "lx" }, { name: "rita", address: "fx" } ]; Sys.onReady(function () { $("#myDv").dataView({
data: items,
itemTemplate: "#template" }) .css("background-color", "lightgray"); }); </script> </head> <body> <div id="myDv"> </div> <div id="template" class="sys-template"> <div>{{name}}</div> </div> </body>

Pretty cool, right? Instead of using the traditional MS AJAX Sys.create helper methods, we’re using a JQuery object for wrapping the div so that we can attach it to a MS AJAX DataView control and set its background color.

Notice that the dataView method (added to the jQuery.fn object) is built on the fly when the JQuery script is listed on the depedencies list passed to the Sys.require method. This is one of those small details that makes life better for everyone…Stay tuned for more.

Oct 23

Master-detail made easy with the DataView control

Posted in Javascript, MS AJAX       Comments Off on Master-detail made easy with the DataView control

We can reuse our knowledge of the previous post to create a master-detail scenario. The idea is simple: we configure our master DataView to show all the elements and then we add a second DataView control that will only show the details of the current selected item on the master DataView. I will spare you from long texts and I’ll jump right away into some code (I’m adapting the code from the previous post):

<body xmlns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
   <div id="master"
        class="sys-template"
        sys:attach="dv"
        dv:data="{{ arr }}"
        dv:selecteditemclass="selected"
        dv:initialselectedindex="0">
      <div sys:command="select">
          <span>{binding name}</span>-
          <span>{binding address}</span>
      </div>
   </div>
   <div id="detail"
        class="sys-template"
        sys:attach="dv"
        dv:data="{binding selectedData, source=$master}">
      <input type="text" sys:value="{binding name}" />
      <br />
      <input type="text" sys:value="{binding address}" />
   </div>
</body>

There are some observations I’d like to make about the previous snippet:

  • you’ll notice that I’ve removed the one-time/one-way bindings of the previous post. I’ve replaced them with live bindings to ensure proper propagation of changes made from the details DataView control;
  • still on the master, I’ve ended up adding two span elements because you can’t put two binding expressions within a single tag;
  • the details DataView control is configured so that it gets its data from the selectedData property of the master DataView control. The selectedData references the object used to fill the current selected item of the DataView control (ie, it references one of the objects from the arr array). Notice that any modifications performed over this object will also be replicated  on the master DataView control because we’ve used live bindings on it between each object of the arr array and each line generated through template instantiation;
  • since we’re applying live bindings to INPUT elements, we can get away with not setting the mode to twoWay (remember that you’ll get the default auto mode which is translated into twoWay for INPUT controls);

And that’s it: as you can see, no JS code and you get updates everywhere.

However, this might not be what you want in some scenarios. You might be interested in having a traditional form where you need to click an edit button for editing an item and then need to click on the confirm on cancel button before making the change persistence. This requires some code, but it’s not that complicated with preview 6. On the next post we’ll see work in this scenario and we’ll see how things have become really really easy! Stay tuned for more.

Oct 23

Updates on preview posts

Posted in Javascript, MS AJAX       Comments Off on Updates on preview posts

As you recall, I’ve started writing about ASP.NET AJAX during preview 5. Meanwhile, preview 6 was out and there were some changes which might break your code. One of the things which changed is the in which way you indicate controls and components declaratively.

With preview 5, you’d use only a string which identifies the ID of the control or component. From preview 6 onwards, you’re supposed to use # prefix to indicate an HTML element search by ID and $ prefix to indicate that you’re searching a MS AJAX component by ID. I’ll try to update the samples I’ve published, but the truth is that, currently, I’m really busy and don’t really know when I’ll have the time to update them. So, if you something doesn’t work for you, take this into consideration and start playing with the new prefixes.

Oct 23

The DataView control and the select command

Posted in Javascript, MS AJAX       Comments Off on The DataView control and the select command

In the previous posts, we’ve met commands and saw how to use them from within a DataView control.What I didn’t mention at the time was that the DataView control understand commands named select. In other words, the DataView understands that type of commands and reacts to them by setting the current selected item.

Currently, the DataView control exposes several properties related with setting the current selected item:

  • initialSelectedIndex: used for setting the index of the default current selected item. This value is only used during initialization time. Setting the default selected item is important in some scenarios (ex.: master-detail scenarios);
  • selectedIndex: read/write property which gets or sets the index of the current selected item;
  • selectedItemClass: you can use this property to pass the name of a CSS class that will be applied to the element that is selected.

The DataView control applies the CSS class you’ve passed into the selectedItemClass in response to a select command (that is, of course, if you don’t cancel the command bubbling from within an existing command handler). The next snippet shows how to take advantage of the automatic handling of select commands:

<head>
  <style type="text/css">
      .sys-template{ display: none;}
      .selected{ background-color: green;}
      #view div{ cursor: pointer;}
  </style>
  <script src="Scripts/MicrosoftAjax/start.debug.js" 
type="text/javascript"></script> <script type="text/javascript"> Sys.require([Sys.components.dataView]); var arr = [{ name: "luis", address: "fx" }, { name: "john", address: "fx" }, { name: "peter", address: "fx"}] </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dv="javascript:Sys.UI.DataView"> <div id="view" class="sys-template" sys:attach="dv" dv:data="{{ arr }}" dv:selecteditemclass="selected" dv:initialselectedindex="0"> <div sys:command="select">{{name}}-{{address}}</div> </div> </body>

And here’s what happens when you click over the second line:

selecteddataview

Bottom line: currently, the only command that is interpreted by the DataView are select commands. The DataView control exposes a couple of poperties which let you define several features related with the selected item. In the next post,we’ll see how we can improve this sample by building a simple master-detail scenario. Stay tuned.

Oct 22

The Sys.create object helper

Posted in Javascript, MS AJAX       Comments Off on The Sys.create object helper

This is becoming quite a long series, but what can I do? There’s simply lots of things to talk about in the new MS AJAX preview 6. As you probably recall (if you’ve been following along since I’ve started writing compulsorily about MS AJAX), we started with code written against preview 5 and then moved to preview 6 when it was released.

One of the new helpers I’ve been using is the new Sys.create object. This object contains several shortcuts for creating components. For instance, in the previous post, I’ve used it to create a new DataView component (instead of relying in the old $create helper).

Sys.create object’s properties are generated dynamically during initialization time. The new script loader object is responsible for populating the object when it parses the info sent to a defineScript(s) method call. In practice, all the components that are specified through the components property of the script info object end up:

  • populating the Sys.components object with information about a specific component;
  • populating the Sys.create object with a new property (named after the script info object’s name property) which references a method created on the fly (this method works like a proxy and is responsible for instantiating the component).

At this time, it might be really interesting to see the code that is generated for one of this helper methods. Lets take a look at what Sys.create.dataView ends up calling:

function anonymous(target, properties) {
  return Sys.loader._callPlugin.call(
        this, "dataView", Sys._create, 
arguments, false,this); }

Btw,I’ve removed the auto-generated comments which do really help with the parameters expected by each function. The Sys.loader._callPlugin is a private method which ends up calling other private methods that are responsible for doing all the work (notice that they need to create a new component, set the indicated properties and register it with the Sys.Application object).

Using the Sys.create object’s method helpers lead to less complexity since they require only two parameters:

  • a reference to the DOM element which will be attached to the component;
  • a JavaScript literal object with the properties and events you want to set.

One of the main differences when you compare this approach with the use of the old $create method is that you no longer separate properties from events: with the Sys.create helpers, everything is mixed up in a single literal object. In practice, the helpers start by checking for an event (ie, then start by trying to find a add_xxx method, where xxx is the name of the property you’ve specified in the literal object) before checking for a property on the component (don’t forget that property means finding a set_xxx method, where xxx is the name of the property).

This shouldn’t really bring any problems because it really is bad practice to give the same name to events and properties. Before ending, there’s still time to mention that MS AJAX preview 6 introduces some helpers: adoNetDataContext, adoNetServiceProxy, dataContext and dataView. And I guess that’s it. Stay tuned for more.

Oct 22

Now that you already know what a command is and how to use them in a declarative scenario, it’s time to keep going and see how we can use them from an imperative only approach. You already know how to “define” templates from JavaScript, so I guess we can concentrate on seeing which JavaScript code we need to generate commands.

If you’ve used a debugger with the previous sample, then you’ve probably noticed that sys:command attributes (and friends) get transformed into  a Sys.UI.DomElement.setCommand method call:

//some code
$element.__mstcindex = $context._tcindex;
Sys.UI.DomElement.setCommand($element,
      "sayHi",
       null,
       Sys.UI.DomElement._ensureGet(
null, $context, ''sys:commandtarget'')); //more code

The Sys.UI.DomElement.setCommand is a helper method which expects the following parameters:

  • a reference to the DOM element which is responsible for generating the command (in this case, $element references the LI that has been created through the template instantiation);
  • a string which identifies the name of the command (sayHi, in the previous snippet);
  • an object which is used as the command’s argument (in a declarative approach, you define it by using the sys:commandargument parameter);
  • a reference to a *DOM* element which is associated with the MS AJX control. Notice that you must really pass a reference to a DOM element and not to a MS AJAX control.

Wit this information,you’ve got all you need to transform the previous example into an imperative approach. However,we can still reduce the code. Remember plug-ins? When we’ve met them, I said that the current release (preview 6) introduced two. We’ve already met the Sys.bind plugin; we’re only missing the Sys.setCommand plugin! Lets start by looking at its definition:

{ name: "ComponentModel",
   isLoaded: !!Sys.Component,
   plugins: [
{
name: "setCommand",
description: "...", plugin: "Sys.UI.DomElement.setCommand", parameters: [
{
name: "commandSource",
description: "The DOM element …"}, {name: "commandName",
description: "The name of the command to raise."}, {name: "commandArgument",
description: "Optional command argument."}, {name: "commandTarget",
description: "DOM element from…"}]}] },

As you can see, these are precisely the same parameters as the ones expected by the Sys.UI.DomElement.setCommand method. And now we’re ready for writing some JavaScript code! Here it is:

<head>
    <script type="text/javascript" 
src="Scripts/MicrosoftAjax/start.debug.js">
</
script> <script type="text/javascript"> var data = [ { name: "luis", address: "fx" }, { name: "john", address: "lx" }, { name: "rita", address: "ams" } ]; Sys.require([Sys.components.dataView]); Sys.onReady(function () { function createHtml(html) { var aux = document.createElement("DIV"); aux.innerHTML = html; return aux.childNodes[0]; } var template = new Sys.UI.Template(
createHtml("<ul><li></li></ul>")); Sys.create.dataView(Sys.get("#myDv"), { itemRendered: function (sender, e) { var current = e.dataItem; var node = e.nodes[0]; node.innerHTML =
current.name + "-" + current.address; Sys.setCommand(
node, "sayHi", null, sender.element); }, itemTemplate: template, data: data, command: function (sender, e) { alert(e.get_commandName()); } }); }); </script> <body> <ul id="myDv"> </ul> </body>

There’s not much to say about the previous snippet because we’ve already look at similar code in previous posts. As you can see, the main difference is that now we’re using the Sys.setCommand plugin for configuring the “sayHi” command.

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

Oct 22

Taking advantage of commands

Posted in Javascript, MS AJAX       Comments Off on Taking advantage of commands

The DataView control supports the concept of a command. In practice, you can think of a command as a “fancy event” which is generated by MS AJAX controls in response to a DOM click event. Commands have an advantage over traditional DOM event handling: for instance, you can easily pass additional information that will be processed by a command hander.

Lets start with a really simple example:

<head>
    <title></title>
    <script type="text/javascript" 
src="Scripts/MicrosoftAjax/start.debug.js">
</
script> <script type="text/javascript"> var data = [ { name: "luis", address: "fx" }, { name: "john", address: "lx" }, { name: "rita", address: "ams" } ]; Sys.require([Sys.components.dataView]); function handleCommand(sender, e) { alert(e.get_commandName()); } </script> </head> <body xmlns:sys="javascript:Sys" xmlns:dv="javascript:Sys.UI.DataView"> <ul class="sys-template" sys:attach="dv" dv:data="{{data}}" dv:oncommand="{{ handleCommand }}"> <li sys:command="sayHi">
{{ name }} - {{ address }}
</li> </ul> </body>

In the previous snippet, we’ve configure the use of commands by:

  • making each click in the inner LI items generate a command named sayHi. Commands can be defined declaratively through the use of the sys:command system attribute. The basic definition of a command relies only in giving it a name (the rest of the information will be picked up automatically);
  • we’ve set up the DataView so that all generated commands are “routed” to the handleCommand method. Since commands can be see as “events on steroids for MS AJAX controls”, then it should surprise you to know that the method will receive a reference to the object that generated the command and an EventArgs derived object which contains info about the command (we’ll return to this topic in the next paragraphs).

Functions that handle commands will always receive a reference to a Sys.CommandEventArgs instance. This “class” expands the Sys.CancelEventArgs class (this means  you’ll get a cancel property which allows you to cancel the bubbling of the command) and adds several new properties:

  • commandName: this property identifies the name of the current command. Notice that you can only have one function for handling commands. If a control generates several commands, then you’ll have to identify the “current” command;
  • commandArgument: references an object which has been previously set during the command configuration (you can do this by using the sys:commandargument attribute);
  • commandSource: identifies the HTML element that was “responsible” for generating the current command (don’t forget that commands are always generated in response to DOM click events).

Besides the sys:command attribute,there are still a couple of other system attributes we can use to influence the generated command:

  • sys:commandargument: you can use this attribute to set the command argument which will be passed when the “current command” is generated. A function that handles a command can get this info by accessing the commandArgument property of the Sys.CommandEventArgs object it receives;
  • sys:commandtarget: used for indicating the MS AJAX control which will be targeted by this command.

You’re probably a little confused with the sys:commandtarget attribute. To illustrate its use,we’ll update the previous example. Take a look at the code(I’m only showing the markup because that’s the only thing that changed):

<ul class="sys-template"
    sys:attach="dv"
    dv:data="{{data}}">
  <li  sys:command="sayHi"
       sys:commandtarget="#customTarget">
    {{ name }}- {{ address }}
  </li>
</ul>
<ul id="customTarget"
    dv:oncommand="{{ handleCommand }}"
    class="sys-template"
    sys:attach="dv"
    dv:data="{{data}}">
  <li>{{name}}</li>
</ul>    

As you can see, we’ve added a new DataView control and we’ve configured it so that any command generated by it will be handled by the handleCommand function. Since we didn’t add any sys:command attribute to that second DataView, you might end up thinking that the previous code won’t do anything useful…

However, you might have noticed that we’ve changed the markup for that first DataView control. If you look carefully, you’ll see that the LI element has also been annotated with a *sys:commandtarget* attribute. That sys:commandtarget attribute ends up influencing the generation of the command: all click made over LI elements maintained by that first DataView control will still be transformed into commands, but now they’ll be dispatched to the #customTarget DataView (and that’s why you’ll still get the handleCommand function call!)

And that’s it for now. There’s still more to come on MS AJAX, so stay tuned.

Oct 21

The Sys.bind plug-in

Posted in Javascript, MS AJAX       Comments Off on The Sys.bind plug-in

We’ve already introduced the concept of MS AJAX plug-in in the previous post. In this post, we’ll explore the Sys.bind plug-in that, as you’ve probably recall, is mapped into the Sys.Binding.bind method. As you’ve probably deduced from its name, you can use this plug-in to establish a binding relationship between two objects. Currently, this plug-in expects until five parameters:

  • target: used for identifying the target of the binding operation;
  • property: string which identifies the name of the property of the target which will be used in the binding operation;
  • source: identifies the source of the current binding operation;
  • path: string which identifies the property of the source object used in the binding relationship;
  • options: literal object used for setting the remaining options of the binding (follows the same rules as the $create helper).

To illustrate its use, we’ll update one of our previous samples so that it uses this new plug-in:

 Sys.bind("#target",
              "value",
              "#source",
              "value",
              { mode: Sys.BindingMode.twoWay });

Notice that we’re simply passing strings for all source and target related parameters: we’re being lazy  (always a good thing when the final result is the same 🙂 – btw, we could go one step further by passing the string twoWay to the mode property!,,) and we’re delegating the work of finding the current objects to the binding itself. As you can see, the rules we’ve mentioned when we talked about the Sys.get helper apply here too.

The Sys.Binding.bind method (don’t forget that Sys.bind ends up delegating all the work to this method) is more flexible than we’re used to (when comparing it with previous versions of MS AJAX): instead of setting all the parameters, you can simply pass a literal object with the parameter values you’re interested in setting. In this case, you’re supposed to use the property names you’d use when calling $create for a binding object. Lets update the previous sample so that it uses this approach:

Sys.onReady(function () {
  Sys.bind({ target: "#target",
    targetProperty: "value",
    source: "#source",
    path: "value",
    mode: Sys.BindingMode.twoWay
  });
});

Even though you don’t gain much (when compared with the previous snippet), the truth is that I like this approach and have suggested its use in the past (ex.: using JSONP). And I guess that’s it. Stay tuned for more on MS AJAX.

Oct 21

The latest release of MS AJAX introduces the concept of plug-ins (which, btw, is different from what you have in other JS frameworks – ex. JQuery). Plug-ins can be seen as simple methods which get added to the “global” Sys object (ie, defining a plug-in results in creating a shortcut in the Sys object). Besides expanding the Sys object with new methods, plug-in registration ends up adding a custom info to the Sys.plugins object (you can think of this object as a global repository for MS AJAX plug-ins).

As you’re probably expecting by now, plug-in registration is done during script definition, ie, when you call the defineScript(s) method. For instance, the template script file (MicrosoftAjaxTemplates.js) introduces a plug-in during its definition. Here’s the code used by it:

{ name: "Templates",
    executionDependencies: [
"ComponentModel", "Serialization"], behaviors: ["Sys.UI.DataView"],plugins: [{
name:"bind",
plugin: "Sys.Binding.bind",
parameters: [
''target'',
{
name:''property'',type:''String''},
''source'',
{
name:''path'',type:''String''},
''options'']
}],
isLoaded: !!(Sys.UI && Sys.UI.Template) },

Registering a plug-in is done by passing an anonymous object and involves setting several properties:

  • name: defines the name of the current plug-in. Internally, the name ends up being used in two places: 1.) it’s used for registering the plug-in with the Sys.plugins object and 2.) it’s used to name the property that is added to the Sys object and which references an anonymous function which ends up calling the “real” plug-in function;
  • plugin: identifies the function which ends up being called when someone accesses the registered plug-in through the Sys.XXX object (in the previous example, that will be the “static” Sys.Binding.bind method);
  • parameters: give information about the parameters expected by the real function passed to the plugin property. A parameter can be represented by a simple string or by an anonymous object with the properties which can describe the parameter (you can use the same values as the ones that are used for adding info that is shown by VS JS intellisense). In the previous snippet, only name and type are used. The name will be used to indicate the name of the parameter; type is there for giving additional info about the current parameter.

As I’ve said above, plug-in definition ends up creating a new anonymous method. Here’s how it looks like:

function anonymous(
target, property, source, path, options) { /// <param name="target" type=""></param> /// <param name="property" type="String"></param> /// <param name="source" type=""></param> /// <param name="path" type="String"></param> /// <param name="options" type=""></param> return Sys.loader._callPlugin.call( this, "bind", "Sys.Binding.bind",
arguments, false, this); }

After registering a plug-in, you can invoke it simply by using its name. For instance, take a look at the following image:

bind

As you can see, Sys now has a method called bind and you even get intellisense for that method call (btw, the previous image was capture in VS 2008)! Notice that you can also get info about a previously registered plug-in (since it got added to the Sys.plugins object during script definition). The next image shows the kind of info you can get from a sys.plugins entry:

plugin

Currently, MS AJAX introduces only two plugins: setCommand and bind. We’ll talk about them in future posts. Stay tuned for more!

Oct 19

In this post, we’ll start applying all the things we’ve met in previous posts and, at the same time, we’ll be making reader William Apken really happy :,,)

William commented a previous post right before preview 6 was released. He was interested in seeing how he could switch templates dynamically. At the time, there wasn’t nothing in the code samples that would help him with that. Things changed with preview 6 and it already has one sample that shows how to do this.

The problem: it defines templates in a declarative way and he’s interested in getting the second template’s HTML from  a web service call. So simplify things, I won’t be showing how to get the HTML: that should be the easy part if you understand the rest of the things we’ll be discussing in this post. Ok, now it’s time to get started…

The idea is to have two templates, one for browsing and another for editing, and switch them at runtime when the user clicks on a button. The preview 6 already has a somewhat similar sample , but we’ll change it so that both templates are created on the fly (ie, they aren’t previously defined in the markup). Let’s look at the code and then we’ll analyze it block by block:

<head runat="server">
    <title></title>
    <script src="Scripts/MicrosoftAjax/start.debug.js" 
type="text/javascript">
</
script> <script type="text/javascript"> Sys.require([Sys.components.dataView]); var templates = {}; Sys.onReady(function() { var items = [ { name: "luis", address: "fx" }, { name: "john", address: "london" }, { name: "rita", address: "lx" } ]; function createHtml(html) { var aux = document.createElement("div"); aux.innerHTML = html; return aux.childNodes[0]; } var browseHtml = "<ul id=''browse''>”+
”<li>{{name}}</li></ul>"
; var editHtml = "<div id=''edit''>”+
”<input type=''text'' sys:value=''{binding name, mode=twoWay}'' />”+
”<input type=''text'' sys:value=''{binding address, mode=twoWay}'' />”+
”</div>"
; templates.browseTemplate = new Sys.UI.Template(createHtml(browseHtml)); templates.editTemplate = new Sys.UI.Template(createHtml(editHtml)); Sys.create.dataView(Sys.get("#view"), { data: items, itemTemplate: templates.browseTemplate }); $addHandler( Sys.get("#change"), "click", function(){ var dv = Sys.get("$view"); dv.set_itemTemplate( dv.get_itemTemplate() === templates.editTemplate ? templates.browseTemplate : templates.editTemplate); }); }); Sys.converters.updateText = function(val) {
return (val === templates.editTemplate ? ''browse'' : ''edit'');
}; </script> </head> <body xmlns:sys="javascript:Sys"> <input type="button" id="change" sys:value="{binding itemTemplate, source={{Sys.get(''$view'')}}, convert=updateText}" /> <div id="view"></div> </body>

There are several interesting things going on here:

  • we’re using the Sys.onReady “event” for running all the code necessary for creating the templates and hooking up the click event which lead to the template switch;
  • we need two templates, so we start by creating the HTML for those templates (notice that these are just simple strings that simulate the HTML obtained from a possible server side call). Notice that we’re also specifying binding expressions. The astute reader will also notice that we’re not using the sys-template class. This makes sense because that CSS class is used for “finding” templates during the DOM parsing and in this case we’re explicitly indicating the HTML element that should be used for the template;
  • the HTML strings end up being passed into a helper method named createHtml. This method creates new DIV node so that it can parse the HTML string by setting its innerHTML property. This is (probably) the easiest way to parse an HTML string (into a DOM node);
  • as we’ve seen, templates don’t require a reference to a page’s DOM element. That means that we can simply create the nodes and pass them to the constructor of the Sys.UI.Template.
  • since we’ll be using these templates for the entire life cycle of the page, I’ve opted for saving them in a global object named templates. This means that we’ll only be creating each template once and then we’ll simply reuse them while the user clicks in the button;
  • we’ve used a binding for ensuring proper update of the button’s text.

Notice that you can also use a slightly different approach if you don’t mind “embedding” the templates in the DOM. For instance, take a look at the following modified JavaScript which embeds the HTML in the page’s DOM:

Sys.require([Sys.components.dataView]);
Sys.onReady(function() {
    var items = [
        { name: "luis", address: "fx" },
        { name: "john", address: "london" },
        { name: "rita", address: "lx" }
    ];

    function createHtml(html) {
        var aux = document.createElement("div");
        aux.innerHTML = html;
        return aux.childNodes[0];
    }
    var browseHtml = "...";//same as before
    var editHtml = "...";//same as before
    document.body.appendChild(createHtml(browseHtml));
    document.body.appendChild(createHtml(editHtml));
    Sys.create.dataView(Sys.get("#view"),
                            {
                                data: items,
                                itemTemplate: "#browse"
                            });
    $addHandler(Sys.get("#change"),
                 "click",
                 function() {
                     var dv = Sys.get("$view");
                     dv.set_itemTemplate(
                        dv.get_itemTemplate() === "#browse"
                          ? "#edit" : "#browse" );
                 });
    Sys.converters.updateText = function(val) {
        return (val === "#edit" ? ''browse'' : ''edit'');
    }

});

We start by creating the nodes and appending them to the page’s DOM. Notice that in this case, we don’t create a template explicitly; we rely, instead, on passing a string (on the form expected by Sys.get helper) to the itemTemplate property. The DataView control is smart enough for checking the type of the property and for instantiating a template when it finds a string.

This might be a good approach for those getting HTML through the jquery’s load method. Stay tuned for more in MS AJAX.

Oct 19

More MS AJAX system attributes…

Posted in Javascript, MS AJAX       Comments Off on More MS AJAX system attributes…

We’ve already met several system attributes in previous posts. As you probably recall, I’ve been using that name for all attributes which are associated with the sys alias (don’t forget that the sys alias use is hardcoded!). In this post, we’ll take a look at some of the special system attributes you can use in your code:

  • sys:class/sys:class-XXX: allow us to use JavaScript code for setting up the CSS class that is going to be applied to the element;
  • sys:innertext: used for setting the innerText property of the element;
  • innerHTML: same as before, but in this case, it’s used for setting the HTML of the element;
  • sys:style-XXX: the passed JavaScript expression decides if the indicated style will be applied to the element;
  • sys:value: used for setting the value of a specific control. Notice that this system attribute’s usage isn’t limited to textboxes; you can, for instance, use it to select an item in a dropdown control.

One of the things you’ll probably need when using the DataView control is to specify different CSS styles for even and odd elements. We’ve got several options, but we’ll start by using the sys:class asttribute:

<head>
    <style type="text/css">
        .sys-template{
            display: none;
        }
        .even{
            background-color: Gray;
        }
        .odd{
            background-color: lightGray;
        }
    </style>
    <script src="Scripts/MicrosoftAjax/start.debug.js" type="text/javascript"></script>
      <script type="text/javascript">
          Sys.require([Sys.components.dataView]);
          var data = [
            { name: "luis", address:"fx" },
            { name: "paulo", address: "lx" },
            { name: "rita",address: "fx" }
        ];

    </script>
</head>
<body xmlns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
    <div id="list"
         class="sys-template"
         sys:attach="dv"
         dv:data="{{data}}">
        <div sys:class=
"{{ $index % 2 === 0 ? ''even'' : ''odd''}}">
{{name}}-{{address}} </div> </div> </body>

As you can see,we’re using the {{ }} one-time/one-way binding expression to ensure that adequate CSS class is used. The sys:class-XXX can also be used to solve this problem (and it even allows more advanced scenarios, where you might need to apply several classes according to several conditions). here’s the equivalent code, this time using the sys:class-XXX attribute (I’m only showing the HTML):

<div id="list"
     class="sys-template"
     sys:attach="dv"
     dv:data="{{data}}">
    <div sys:class-even="{{ $index % 2 === 0}}"
         sys:class-odd="{{ $index % 2 !== 0}}">
        {{name}}-{{address}}
    </div>
</div>

The sys:class-XXX approach ends up evaluating each condition and applying the associated XXX class if that condition is true (in the previous example, the used conditions exclude each other and that’s why you’ll end up with only  single class name: even or odd). Since our CSS classes are used for setting only the background-color style attribute, we could also use the sys:style-XXX attribute for setting the background color of each element. The use of this attribute is similar to the sys:class-XXX, but in this case, you’re supposed to use the CSS property name you’re interested in setting:

<div id="list"
     class="sys-template"
     sys:attach="dv"
     dv:data="{{data}}">
    <div sys:style-background-color=
"{{ $index % 2 === 0 ? ''gray'' : ''lightgray''}}">
{{name}}-{{address}} </div> </div>

We’ve already met the sys:value before, so we won’t be showing how to use it here. The sys:innerhtml and sys:innertext follow similar rules, but end up setting different properties. In these cases, they end up setting, respectively, the innerHTML and innerText properties of the elements to which they’re applied.

And this sums it up quite nicely (I think). It’s been a long series of posts…there’s still much to discuss though, so stay tuned for more on MS AJAX.

Oct 19

Using nested tempates

Posted in Javascript, MS AJAX       Comments Off on Using nested tempates

The last post might have left you thinking that templates still need some working. After all, using sys:beforecode and sys:aftercode doesn’t really look well, right? Yes, I agree: it’s a little bit ugly. In fact, lets recover the (offending?) code we’ve used here in that sample:

<p
    sys:codebefore="for(var pos in contacts){"
    sys:codeafter="}">
    {{contacts[pos]}}
</p>

Now, the question is: can we improve our code and remove those ugly sys:beforecode and sys:aftercode attributes from our markup? If you’re an Obama supporter, you already know the answer: “Yes, we can!

The answer lies in using nested templates! Lets update the code to use nested templates (the JavaScript is the same, so I’ll just put the updated markup):

<body xmlns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
    <div id="list"
         class="sys-template"
         sys:attach="dv"
         dv:data="{{data}}">
        <div>
            {{name}}<br />
            <div id="innerTemplate"
                class="sys-template"
                sys:attach="dv"
                dv:data="{{contacts}}">
                <p>
                {{$dataItem}}
                </p>
            </div>

        </div>
        <hr sys:if="{{ ($index + 1) % 2 === 0 }}" />
    </div>
</body>

Ok, lets see what we’ve got here…

The first thing you’ll notice (when comparing with the previous example) is that we’ve added a new container (notice that P is now wrapped into a DIV element). This new container will be attached to a new DataView control (notice the sys:attach attribute usage), which introduces its own template.

We’re taking advantage of contexts and we’re using the “current” contacts array for feeding items to the inner template (defined within the inner DataView control). Notice that each item in the contacts array is a string: from a practical point of view, that means that we’ll be printing the current contact through the $dataItem pseudo-column (instead of accessing one of its properties by name,like we did in all our previous samples).

And that’s it. More about ASP.NET AJAX in future posts.

Oct 19

We’ve already seen that templates let us use pseudo-columns for accessing specific context information. In this post, we’ll be talking about a related subject: including code in a template through the use of sys: attributes. Currently, you’ve got the following options:

  • sys:codebefore: executes the specified JavaScript expression before rendering each element;
  • sys:codeafter: executes the specified JavaScript expression after generating each element;
  • sys:if: generates the HTML of the current element if the associated condition is true.

From the three, I think that sys:if will be the most used one. So lets start with it, shall we?

<head runat="server">
    <style type="text/css">
        .sys-template{
            display: none;
        }
        .selected{
            background-color: Gray;
        }
    </style>
    <script src="Scripts/MicrosoftAjax/start.debug.js" type="text/javascript"></script>
      <script type="text/javascript">
          Sys.require([Sys.components.dataView]);
          var data = [
            { name: "luis", address: "funchal" },
            { name: "paulo", address: "lisbon" },
            { name: "rita", address: "oporto" }
        ];
    </script>
</head>
<body xmlns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
    <div id="list"
         class="sys-template"
         sys:attach="dv"
         dv:data="{{data}}">
        <div>{{name}}-{{address}}</div>
        <hr sys:if="{{ ($index + 1) % 2 == 0 }}" />
    </div>
</body>

The previous code will show a separator line (notice the <hr>) after rendering each two items (notice that we must adapt the $index pseudo-column since it’s zero based). As you can see, the only thing it does is to decide if the current HTML element where it’s applied should be rendered or not. And that’s it…really!

The sys:codefebore and sys:codeafter might seem a little weird…the truth is that you think of them as being the equivalent of the <% %> pair you already know so well from ASP.NET :,,).

Here’s a quick example (which can be improved by using nested templates, but we’ll leave that for a future posts – for now, concentrate only on the use of the sys:codebefore and sys:codeafter attributes!):

<head runat="server">
    <style type="text/css">
        .sys-template{
            display: none;
        }
        .selected{
            background-color: Gray;
        }
    </style>
    <script src="Scripts/MicrosoftAjax/start.debug.js" type="text/javascript"></script>
      <script type="text/javascript">
          Sys.require([Sys.components.dataView]);
          var data = [
            { name: "luis", contacts: ["123123123","222222222"] },
            { name: "paulo", contacts: ["123123123", "333333333"] },
            { name: "rita", contacts: ["555555555"] }
        ];

    </script>
</head>
<body xmlns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
    <div id="list"
         class="sys-template"
         sys:attach="dv"
         dv:data="{{data}}">
        <div>
            {{name}}<br />
            <p
                sys:codebefore="for(var pos in contacts){"
                sys:codeafter="}">
                {{contacts[pos]}}
            </p>
        </div>
        <hr sys:if="{{ ($index + 1) % 2 == 0 }}" />
    </div>
</body>

We’ve changed the objects used for feeding the DataView control: now each object has a name and a collection of contacts. We’re interesting in showing the contacts (one per line) of each of the objects. If you’re using ASP.NET MVC and the web forms view engine, then you’d probably use a for sprinkled with HTML code in it…probably something like this:

<% for( var t in obj.Contacts ){%>
    <p><%= t %></p>
<% }%>

Not pretty, but that’s what most people end up doing in ASP.NET MVC 1.0 (again, when using the web forms view engine). As you can see, we start with putting the for condition on one line and are forced to close the open brace in another line. And that’s  precisely what’s going on with the previous JavaScript sample:

<p
    sys:codebefore="for(var pos in contacts){"
    sys:codeafter="}">
    {{contacts[pos]}}
</p>

Since contacts is an array, pos will return the current index which we can reuse for getting the current item from the contacts array. I think that comparing this code with the previous ASP.NET <% %> example is the best way to understand this feature. I guess you won’t be using it much, but if, by any chance, you feel that you need something like that, you can use the sys:codebefore and sys:codeafter attributes.

And I guess that’s it. Keep tuned for more in MS AJAX.

Oct 19

Declarative vs imperative approach: which to choose?

Posted in Javascript, MS AJAX       Comments Off on Declarative vs imperative approach: which to choose?

Now that we’ve seen how to use two approaches (declarative vs imperative) for defining templates, you might be asking yourself which one you should pick. As always, I’d say that there is no definitive answer here. Having the option for both is great and means that templates can get used by everyone.

Having said this, I must say that I find it appropriate to base my templates on a declarative approach. Nobody can deny that it’s just “too easy” to build templates declaratively and I’ll be using  them whenever I require templates. However, there still might be some reason which forces you from adding the declarative markup needed for template definition to the HTML of the page.

In those cases, the easiest strategy is to create a dumb node and use the itemRendering for generating the correct HTML. As we’ve seen, template contexts make it easy to get back the data used for instantiating the template and that should be enough for all the scenarios you might face.

Bottom line: I think the declarative approach will be the most used when you need to define templates, but remember: if you want, you can do everything from JavaScript.

Oct 19

The new script loader object – part VI

Posted in Javascript, MS AJAX       Comments Off on The new script loader object – part VI

As we’ve seen in previous posts, the new preview 6 introduced a new Sys.loader object. This is a fantastic object which I guess most of us will end up depending on for getting the necessary JavaScript files required by a page. Even though it’s great to let it download the files on demand, the truth is that there are some cases where you’re probably interested in combining all the files into one (yes, I did get some questions about this feature after publishing the previous posts on the script loader object). Combining resources is a known strategy for improving the performance of a web application.

The good news is that script combining is supported by the script loader object! Before we go on, it’s important to understand that the “physical” process of combining script files can only be done in the server side (you can build your combined script files by hand or you can rely in a handler for doing that for you). When I say that the script loader object supports combining scripts, what I’m trying to say is that it understands the concept of combining scripts and that you can give him that info when you define a script through the defineScript(s) method. For instance, take a look at the way MicrosoftAjax.js file is defined:

// Composite Scripts
{ name: "MicrosoftAjax",
   releaseUrl: "%/MicrosoftAjax.js",
   debugUrl: "%/MicrosoftAjax.debug.js",
   executionDependencies: null,
   contains: ["Core", "ComponentModel",
"History","Serialization", "Network",
"WebServices", "Globalization"] }

The contains property is used for specifying that the current script combines several scripts that have been previously registered. In this case, the MicrosoftAjax.js file contains many of the features supported by the library (as you can see by looking at the array that is passed into the contains property). Composite scripts are registered under the Sys.composites object. If you stop your code at a debugger, you’ll notice that it contains a reference to a script info object registered with the MicrosoftAjax name:

composites

By now, I guess that the question many of you are asking is: when will the script object download a composite script? It will only download it *automatically* if it sees that you’ve required all the features indicated in the contains property of a previously “registered” script. For instance, specifying something like this:

Sys.require([Sys.scripts.Core, Sys.scripts.ComponentModel,
            Sys.scripts.ApplicationServices,//not in microsoftajax
            Sys.scripts.Network, Sys.scripts.Serialization,
            Sys.scripts.History, Sys.scripts.Globalization,
            Sys.scripts.WebServices]);

means that the script loader will download the MicrosoftAjax.js file + the MicrosoftAjaxApplicationServices,js file (notice that the application services code – used in authentication, roles and profiles – isn’t defined within the MicrosoftAjax.js file!).

The second option you have is to force the download of a composite script file. This is easy because you can pass a reference to a composite when you call the Sys.require method:

Sys.require([Sys.composites.MicrosoftAjax]);

This will also end up downloading the MicrosoftAjax.js file. Before you go on combining all your script files, do remember that you should only do that after measuring and not because someone has said that script combining improves performance (it does, but as always, there’s a balance between combining and using the default files, especially when you’re using CDNs and rely on browser and proxy caching!). Btw, I expect that we’ll get some predefined combined scripts for the final version of the platform which match the most common scenarios.

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

Oct 19

In the previous posts, we’ve migrated our code from a pure declarative approach to an imperative approach. Today we’ll improve our last example and we’ll see how we can perform some interesting operations by using the Sys.UI.TemplateContext object obtained by instantiating a template (ie, obtained when you call instantiateIn over a Sys.UI.Template instance).

Lets assume that we need to improve our HTML used for the template. For instance, we want to to put the name and address info into SPAN nodes. Looking at the previous sample, it’s obvious that we could simply add the necessary tags to the string passed to the innerHTML property:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    e.nodes[0].innerHTML = "<span>" + data.name + 
"</span>-<span>" + data.address + "</span>"; }

This would solve the problem! However, I’m disallowing this approach for this post because it wouldn’t allow us to explore the cool things we can do with the Sys.UI.TemplateContext object! Instead, lets assume that we must use the following HTML for the template (we’re still using an imperative approach here!):

var helper = document.createElement("ul");
helper.innerHTML = "<li><span id=''name''></span>” + 
“-<span id=''address''></span></li>"
;

Now, the question is: how do we access the span nodes from within the itemRendered events? Option number 1 relies on navigating through the created nodes. If you recall our last sample, you’ll remember that the ItemRendered event receives an instance of a Sys.UI.TemplateContext object. We can use this object to get a reference to the HTML created from the template instantiation (e.nodes returns a collection of nodes; in the previous example, there’s only one top node – the LI element). Here’s the code that shows how to set up the span’s content by using this strategy:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    var nameNode = e.nodes[0].childNodes[0];
    var addressNode = e.nodes[0].childNodes[2];
    nameNode.innerHTML = data.name;
    addressNode.innerHTML = data.address;
}

As you can see,we use the childNodes property for getting a reference to the correct elements we want to customize. The previous code might caught you off guard…just remember: childNodes returns a reference to all the child nodes of the LI element  (including text nodes!).

Now,if you paid attention to the initial definition of the HTML used by template, you’ve probably noticed that we gave IDs to the inner spans. I did that for a reason: to allow me to get them in a fast, non-error prone way. When you have IDs, you can use the Sys.get helper for getting a reference to the element. Take a look at the improved code:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    var nameNode = Sys.get("#name", e);
    var addressNode = Sys.get("#address", e);
    nameNode.innerHTML = data.name;
    addressNode.innerHTML = data.address;
}

If you’ve read the previous post on Sys.get, you’ll recall that the parameter used as a second parameter is used as the context for the search, ie, it limits the search to that context. You probably recall that the only restriction applied to the context parameter was that it should expose a get method which is responsible for doing all the work. In practice, that means that we can simplify the code by using that method directly:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    var nameNode = e.get("#name");
    var addressNode = e.get("#address");
    nameNode.innerHTML = data.name;
    addressNode.innerHTML = data.address;
}

You might be a little worried because you might be thinking that template instantiation is introducing duplicate IDs in your page. It might happen, but not in the template instantiation code. Let me be clear here: template instantiation code will always generate elements with different IDs (ie, if you concentrate on the HTML generated in the previous example, you’ll see that the HTML for the DataView control doesn’t have any duplicated IDs). However, it cannot guarantee no duplications at page level since that would mean lots and lots of processing (it expects that you, the developer, configure the template correctly so that the generated IDs won’t introduce any duplication at page level). Btw, template instantiation will only generate IDs for the elements that have an ID; if you don’t set the ID in the HTML elements that define the template, none will be generated.

The next image shows the resulting HTML introduced in the page:

templateInstantiation

As you can see, the final IDs is obtained by combining the ID  you’ve used in the template with the position of the row in the data source used to feed the DataView control.

Besides the get method, the Sys.UI.TemplateContext introduces other methods you might find useful:

  • getInstanceId: this method expects a string with the base ID and generates a new ID based in the position of the template instantiation in the container. This method is used internally for getting the ID that is applied for each generated element;
  • query: lets you pass an expression and returns the element(s) that match it. Internally, this ends up calling the same method that is used by the public Sys.get helper (the main difference is that it can return several nodes, instead of returning a single one).

Before ending, you should know that the DataView saves all the Sys.UI.TemplateContext instances used during template instantiation. You can access this collection because the DataView control exposes the read-only contexts property (get_contexts). In practice, this means that you can, at any moment, access the data that has been used to generate any of the lines generated by the DataView control . Pretty cool, right?

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

Oct 18

[Update: with preview 6, Sys.loader.debug is replaced by the Sys.debug property]

We’ve already met several features introduced by this awesome new object. However, in the comments of one of the previous posts, William Apken asked about the CDN path for preview 6. That reminded me that I still haven’t presented all the features associated with this object. And that’s why in this post we’ll be talking about paths to scripts and on how we can influence them.

Btw, and before going, the base path for the CDN release of preview 6 is  http://ajax.microsoft.com/ajax/beta/0910/

Ok, now that you know the base URL, you have two options for using CDN preview 6 hosted  files in your app:

  • you can use the script tag and specify an absolute address on it. For instance, if you’re just adding the start.js file, you can simply use the absolute URL for the CDN and then all other files will be downloaded from there;
  • you can use the Sys.loader.basePath property for influencing the place from where the script files are loaded.

With the last option, you can, for instance,load some files from place A and others from place B. For instance,consider the code  we’ve used in the imperative post – take II…by using the second approach, we can easily influence the download of the files by dropping the next line of code before calling the Sys.require method:

Sys.loader.basePath = "http://ajax.microsoft.com/ajax/beta/0910/";

However, start.js would still be loaded from the local server because we’re using a relative path for that file!

In my opinion, you probably won’t be using this property much since the easiest option is to use a relative path to the start.js file and then change it to CDN when you deploy your app Yes, I’m assuming you’re downloading the JS files on the fly through the Sys.loader object. If that is not the case, then you’d probably be ok by changing the path for the loader’s file (traditionally, this might start.js, microsoftajaxcore.js or microsoftajax.js) and then immediately setting the basePath property before including the other JavaScript files (this would let you use relative paths for those other JavaScript files).

Btw, and since we’re talking about influencing paths, you should also notice that the Sys.loader has another interesting property: I’m talking about the debug property. When this property is set to true, you’ll end up downloading the debug files (ex.: microsoftajaxcore.debug.js). Setting it to false means getting the release files:

Sys.debug = false;

In case you’re wondering, these features are only possible due to the way debug and release urls were specified during the defineScripts method call. For instance, take a look at the following snippet:

loader.defineScripts({
    releaseUrl: "%/MicrosoftAjax" + "{0}.js",
    debugUrl: "%/MicrosoftAjax" + "{0}.debug.js",
    codependencies: ["Core"]
}, …

As you see, we’re using the % char for specifying a marker that will be replaced for the script object’s basePath property. Another interesting thing you’ve (probably) noticed is that you can use the {0} for replacing a portion of the string with the name of the current script info object (this strategy is used by MS AAJX for simplifying the registration code for each of the modules that compose the library).

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

Oct 17

On the BLOCKED SCRIPTSys entry…

Posted in Javascript, MS AJAX, Trivia       Comments Off on On the BLOCKED SCRIPTSys entry…

Unfortunately, it seems like CS is escaping my JavaScript code. Whenever you see BLOCKED SCRIPTSys, it should be javascript :Sys (without any space). Sorry for that, but I believe there’s nothing I can do about it now…

Oct 17

In this post, we’ll be talking about the new Sys.get helper introduced by preview 6 of MS AJAX. Currently, the method can be used for getting a reference to a DOM element or a MS AJAX component and it exposes the following signature:

function get(selector, context)

The method expects two parameters (the second is optional):

  • selector: generally, you’ll pass a string which identifies the element you want;
  • context: used for limiting the search to a specific context. All contexts should expose a get method which can be used for getting the element;

Before going on, it’s important to keep in mind that this method will always return a reference to a single element (or null, if it can’t find at least one element that satisfies the passed criteria)!

For now, we’ll ignore the context parameter and will simply concentrate in the selector parameter. The passed in string can be in one of the following forms:

  • $something: tries to get a reference to the component named something;
  • #something: tries to get a reference to the DOM element with the ID something;
  • .something: returns the first DOM element with the class something;
  • something: returns the first DOM node named something (ie, it returns a reference for the first <something> found in the current context.

You may be thinking that this is a rather limited, especially if you compare it with, say, JQuery. Well,there are good news here! If you’re a JQuery fan,then you’ll be pleased to know that if you’ve loaded it then the Sys.get method will delegate the call in the jQuery method if the passed selector doesn’t match any of the rules presented in the previous list (for instance, passing something like “div span” ends up using JQuery if it has also been loaded in the page). I hate to repeat myself, but it’s important to recall that, even in this case, you’ll only get a reference to the first DOM node that satisfies that selector.

One additional note before seeing an example: if selector isn’t a string, it will be automatically returned from the Sys.get method invocation. Ok, lets see s really simple example:

<body xlmns:sys="javascript:Sys"
      xmlns:dv="javascript:Sys.UI.DataView">
    <ul id="dv" class="sys-template"
        sys:attach="dv"
        dv:data="{{items}}">
        <li>{{name}} - <span class="test">{{address}}</span></li>
    </ul>
    <input type="button" id="bt" value="get info" />
</body>
<script type="text/javascript">
    var items = [
        { name: "luis", address: "fx" },
        { name: "john", address: "london" },
        { name: "rita", address: "lx" }
    ];

    Sys.require([Sys.scripts.Templates, Sys.scripts.jQuery]);

    function pageLoad() {
        $addHandler(
            Sys.get("#bt"), //select by ID
            "click",
            function() {
                alert("component with ID dv: " + 
Sys.get("$dv").get_selectedIndex()); alert("first DOM with css class: " +
Sys.get(".test").innerHTML); alert("first tagname: " +
Sys.get("li").innerHTML); alert("jquery returns first node: " +
Sys.get("li span").innerHTML); }); } </script>

The previous snippet illustrates several selector options:

  • the reference to the DOM element used by the $addHandler method is obtained through the DOM ID selector (#);
  • getting a component is really simple: we just need to indicate that through the $ symbol;
  • getting the first element with a specific CSS class name depends on starting the selector string with a dot (.);
  • since we’ve also loaded jquery (note the Sys.require call), we can also use more complex expressions. However, don’t forget that even though the expression might result in a JQuery object which wraps several DOM nodes, the Sys.get method will only return a single DOM element (the first one).

You’re probably expecting me to talk about that second parameter (context), but I’ll have to leave it for a future post because we still haven’t discussed how the DataView control uses contexts internally for rendering items (we’ve mentioned it when we started talking about templates and declarative/imperative approaches, but we still to discuss it more thoroughly for things to make sense).

Stay tuned for more in MS AJAX.

Oct 16

In part three, we saw that we even have intellisense for requiring on-demand download of the necessary files for a specific feature or script. Even though that will probably be its most common use, you can also use the script loader object for downloading scripts which haven’t previously been “defined” through the Sys.loader.defineScripts method. In these scenarios, the loadScripts method is your friend!

Once again, we’ll build in the previous example and we’ll update it so that we use this method for ensuring proper loading of the required scripts:

<head>
    <title></title>
    <script src="Scripts/MicrosoftAjax/start.debug.js" type="text/javascript"></script>
</head>
<body>
    <input type="button" value="invoke B" id="bt" />
</body>
<script type="text/javascript">
    Sys.onReady(function() {

        function loadAndCallB() {

                Sys.loader.loadScripts( ["a.js", "b.js"],
                                        function(){ B(); } );
        }
        var bt = Sys.get("#bt");
        if (bt.attachEvent) {
            bt.attachEvent("onclick", loadAndCallB);
        }
        else {
            bt.addEventListener("click", loadAndCallB, false);
        }
    });
</script>

The code is similar, but there are some interesting differences:

  • in this case, you need to pay attention to the loading order of the scripts. Since you haven’t previously defined them (through the defineScripts method),the loader object can’t really understand that it needs to load script A before running the callback method on B. Even if you modify script b.js so that its registerScript method specifies the dependency in A,you’ll still need to have previously defined (ie, called the defineScripts method for) A so that it understand the execution dependency between A and B;
  • the loadScripts method expects an array of urls, a callback function (will be invoked when all the scripts have been downloaded) and a custom context which will be passed to the callback function (we didn’t use this in the previous sample);
  • the loadScripts method is smart enough for not doing duplicated downloads. That means that the second click on the button will simply redirect to the callback function (without downloading the scripts again).

And I guess this sums it up for now. We’ve already seen so many features introduced by preview 6 and there are still a ton of them to talk about. I guess this will keep me occupied in the next couple of days. Stay tuned for more on MS AJAX.

Oct 16

The new script loader object – part III

Posted in Javascript, MS AJAX       Comments Off on The new script loader object – part III

In the previous posts, we’ve met the new script component loader. As we’ve seen in the latest post, the new script loader object can helps us:

  • improve the performance of our applications by allowing parallel downloads of several script files (which need to be slightly changed to work properly with it). This is possible due to the introduction of the concept of execution dependency;
  • ensure proper initialization of those script files since it takes execution dependencies and dependencies into account before running a callback wrapper method which is responsible for initializing the library.

These features are cool and will help anyone doing web development. But the object goes a little bit further: it can also automatically download the required files for you… but only if you ask it, of course :,,)

As you’ve probably noticed, you’re supposed to define the debugUrl and releaseUrl properties on all script info objects used for defining a specific script. These two properties indicate the path to the release and debug script files (notice that you don’t really need to have two files, though that is highly recommended because you’ll typically need to read the code in debug mode and you’ll want it minified for release mode).

Since the script loader object has access to this info, it can easily download the files as needed when you ask him to do that. Let’s go back to our previous example and update its HTML so that we let the script loader object fetch the scripts as needed:

<head>
    <title></title>
    <script src="Scripts/MicrosoftAjax/start.debug.js" type="text/javascript"></script>
    <script type="text/javascript">
        Sys.loader.defineScripts( null, [
                                    {
                                      releaseUrl: ''a.js'',
                                      debugUrl: ''a.js'',
                                      name: ''A''
                                    },
                                    {
                                      releaseUrl: ''B.JS'',
                                      debugUrl: ''B.JS'',
                                      name: ''B'',
                                      executionDependencies:[''A'']
                                    }] );
    </script>
</head>
<body>
    <input type="button" value="invoke B" id="bt" />
</body>
<script type="text/javascript">
    Sys.onReady(function() {
        function loadAndCallB() {
            Sys.require(
                [Sys.scripts.B], //feature needed
                function() { B(); } //callback method
                );
        }
        var bt = document.getElementById("bt");
        if (bt.attachEvent) {
            bt.attachEvent("onclick", loadAndCallB);
        }
        else {
            bt.addEventListener("click", loadAndCallB, false);
        }
    });
</script>

As you can see, we removed the script nodes that forced the loading of the JavaScript files. We’re doing the clicking hook up from the Sys.onReady event. This is new and lets you interact with the DOM when it’s ready for it. Notice that in this case we don’t event load the core MS AJAX lib and rely on using some “old tricks” for setting up bt’s click handler. The most interesting thing happens within the loadAndCallB method:

Sys.require(
    [Sys.scripts.B], //feature needed
    function() { B(); } //callback method
    );

We’re using the require method to force the download of the script registered with the name B.  If you try it yourself, you’ll see that you have intellisense (notice the script on the header which defines scripts A and B!). The script object is really smart and will do all the work for you: it will get both scripts (since they’re using execution dependencies, it doesn’t really matter which one arrives first) and then it will call the method you’ve passed to the Sys.require method (btw, the callback method is needed because script download and parsing is done asynchronously).

The require method lets you pass an additional parameter for passing a specific context to the callback method.

If you want, you can specify several features in the array you passed to Sys.require method. And notice that you can also mix script references with other features. For instance, the following call would force the download of all files necessary for running script B and for using the DataView component:

Sys.require(
    [Sys.scripts.B, Sys.components.dataView], //feature needed
    function() { B(); } //callback method
);

And don’t thing we’re finished! This is just one of the ways you can force the Sys.loader to load the necessary JS files. In the next post, we’ll see an alternative way of forcing the download of scripts. Stay tuned for more.