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"}
    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">
  <style type="text/css">
          display: none;
  <script src="Scripts/MicrosoftAjax/start.debug.js" 
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.

9 comments so far

  1. Bertrand Le Roy
    6:42 pm - 10-28-2009

    .sort = SortOrder[$(this).text()]; 🙂

  2. luisabreu
    7:25 pm - 10-28-2009

    oh damn, you do really read them, don”t you? 🙂


  3. william apken
    11:48 pm - 10-28-2009


    What is the correct line for the fetchParameters:

    It appears that { orderby: ”FirstName” } is not working for me.

    myDV = Sys.create.dataView(“#view”,
    dataProvider: myDC,
    fetchOperation: “Customer”,
    fetchParameters: { orderby: ”FirstName” },
    autoFetch: true,
    itemTemplate: templates.browseTemplate

    Thank you

  4. william apken
    5:57 am - 10-29-2009

    Can we see an example of the dataView being created with the Sys.create.dataView not declaratively. Also have the ability to swap out templates( as you have done in a previous post) but have the html be a ?

    Everything starting moving alone real well as long as my templates were .

    Tried to convert templates to a table (still working on my datagrid) and it all broke.

    thank you.

  5. luisabreu
    2:13 pm - 10-29-2009

    William, you want a sample with templates based on tables? (with swapping)

  6. william apken
    2:48 pm - 10-29-2009

    Yes. With no declarative code. It appears that when you put into the template it breaks.

    If you put a table into the html section it works.
    The code below works:



    If the template includes this works fine.

    The code below is what makes it break.
    var editHtml = “{{City}}{{State}}{{Zip}}”;

  7. william apken
    5:32 pm - 10-29-2009

    It appears that the coded I wrote about in my last comment is not the cause of the error.

    I changed the code to just list the bindings.
    {{FirstName}}{{LastName}}. It still breaks in the function listed below:

    function Sys$UI$Template$recompile() {
    var element = this.get_element(),
    code = [” $index = (typeof($index) === ”number” ? $index : __instanceId);n var $component, __componentIndex, __e, __f, __topElements = [], __d = 0, __p = [__containerElement], $element = __containerElement, $context = new Sys.UI.TemplateContext(), $id = function(prefix) { return $context.getInstanceId(prefix); };n $ = (typeof(__data) === ”undefined” ? null : __data);n $context.components = [];n $context.nodes = __topElements;n $context.dataItem = $dataItem;n $context.index = $index;n $context.parentContext = __parentContext;n $context.containerElement = __containerElement;n $context.insertBeforeNode = __referenceNode;n $context.template = this;n with($dataItem || {}) {n”],
    nestedTemplates = [];
    this._buildTemplateCode(nestedTemplates, element, code, 0);
    code.push(“}n $context._onInstantiated(__referenceNode);n return $context;”);
    code = code.join(””);
    element._msajaxtemplate = [this._instantiateIn = new Function(“__containerElement”, “__data”, “$dataItem”, “$index”, “__referenceNode”, “__parentContext”, “__instanceId”, code), nestedTemplates];

    the last line of this function is throwing the error.

    It appears it does not like trying to place an outside template into the table body.

    I may have my table formated wrong. I did try to copy your example where you used a table.

    Thank you

  8. luisabreu
    6:00 pm - 10-29-2009

    william, i”velooked at the code now. you cannot create tables like that. try doing something like this:

    var tmpl = “{{name}}{{address}}”;
    var r = document.createElement(“div”);
    r.innerHTML = tmpl;
    var tpl = r.childNodes[0].childNodes[0];

    then pass tpl to the Template constructor and it should work.

  9. william apken
    9:07 pm - 10-29-2009

    That worked. Thanks.