October 2009 - Posts

Getting started with the DataContext object
Fri, Oct 30 2009 12:50

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.

DataViews, DataViews and more DataViews: DataViews everywhere!
Thu, Oct 29 2009 16:19

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!

by luisabreu | with no comments
Filed under: ,
The global:: qualifier in C#
Thu, Oct 29 2009 13:16

Today I was a little bit surprised when I was asked if we really needed the global:: qualifier. If you’ve been doing C# for some time, the answer is (absolutely) yes. However, things might not be so clear for a beginner (btw, the question was asked in the context of auto-generated by VS which used it to qualify the name of a base class). The best way to understand it is to write a quick sample where you might really need to use this qualifier:

class Test {
    public void SayHi() {
        Console.WriteLine("hi global");
    }
}
namespace ConsoleApplication1 {
    class Test {
        public void SayHi() {
            Console.WriteLine("hi within");
        }
    }
    class Program {
        static void Main(string[] args) {
            new Test().SayHi(); //???
        }
    }
}

The previous sample is valid C# code (notice that we’ve introduced two classes with *similar* names – Test and ConsoleApplication.Test). The real question is: what happens when we create a new Test instance from within the Main method?

In the previous sample, we’ll end up instantiating ConsoleApplication1.Test. And what if we wanted to instantiate Test? Yes, the answer is the global::  qualifier. After showing this example, there really wasn’t any doubt regarding the usefulness of the global::qualifier: you’ll need it in some cases to force the use of a specific type or name.

by luisabreu | 5 comment(s)
Filed under:
DataView and remote web service invocation: adapting the data returned from the server
Thu, Oct 29 2009 11:20

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.

by luisabreu | with no comments
Filed under: ,
PowerShell 2.0 RTMed
Thu, Oct 29 2009 10:07

It seems like it introduces a ton of new stuff…

by luisabreu | with no comments
Filed under:
Using the fetchParameters property to pass values to the web service method
Wed, Oct 28 2009 16:38

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="BLOCKED SCRIPTSys" xmlns:dv="BLOCKED SCRIPTSys.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.

Feeding the DataView control with data returned from a Web Service – take II
Wed, Oct 28 2009 15:48

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="BLOCKED SCRIPTSys" xmlns:dv="BLOCKED SCRIPTSys.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.

by luisabreu | with no comments
Filed under: ,
Feeding the DataView control with data returned from a Web Service
Wed, Oct 28 2009 12:37

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="BLOCKED SCRIPTSys" xmlns:dv="BLOCKED SCRIPTSys.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!

DataView control: other interesting events
Tue, Oct 27 2009 10:12

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.

Shameless plug for João Afonseca
Mon, Oct 26 2009 20:26

I’m sorry, but I couldn’t resist sharing this with you guys (especially if you’re a soccer fan ; ) ). btw, he’s my nephew…and yes, I’m proud :)

by luisabreu | 1 comment(s)
Filed under:
Master-detail made easy with the DataView control – take II
Mon, Oct 26 2009 16:34

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="BLOCKED SCRIPTSys"
      xmlns:dv="BLOCKED SCRIPTSys.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 BLOCKED SCRIPT

<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.

JQuery integration
Mon, Oct 26 2009 11:08

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.

Super Loeb
Sun, Oct 25 2009 22:09

Does it again! Fantastic come back from the best rally driver of all times…just watch this if you have any doubts…

by luisabreu | with no comments
Filed under:
Master-detail made easy with the DataView control
Fri, Oct 23 2009 15:22

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="BLOCKED SCRIPTSys"
      xmlns:dv="BLOCKED SCRIPTSys.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.

Updates on preview posts
Fri, Oct 23 2009 14:48

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.

by luisabreu | with no comments
Filed under: ,
The DataView control and the select command
Fri, Oct 23 2009 14:25

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="BLOCKED SCRIPTSys" xmlns:dv="BLOCKED SCRIPTSys.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.

The Sys.create object helper
Thu, Oct 22 2009 13:47

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.

by luisabreu | with no comments
Filed under: ,
Taking advantage of commands – take II
Thu, Oct 22 2009 12:18

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.

Taking advantage of commands
Thu, Oct 22 2009 11:20

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="BLOCKED SCRIPTSys" xmlns:dv="BLOCKED SCRIPTSys.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.

Swine flue controversy
Wed, Oct 21 2009 21:35

I’ve just received an email which reference this interview. It really makes you think…

by luisabreu | 3 comment(s)
Filed under:
More Posts Next page »