Using the fetchParameters property to pass values to the web service method

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

Filed under: ,

Comments

# Bertrand Le Roy said on Wednesday, October 28, 2009 1:42 PM

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

# luisabreu said on Wednesday, October 28, 2009 2:25 PM

oh damn, you do really read them, don't you? :)

thanks.

# william apken said on Wednesday, October 28, 2009 6:48 PM

Luis,

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

# william apken said on Thursday, October 29, 2009 12:57 AM

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 <table>?

Everything starting moving alone real well as long as my templates were <ul><li>.

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

thank you.

# LA.NET [EN] said on Thursday, October 29, 2009 5:20 AM

Yesterday I’ve ended up receiving an interesting question regarding the code I’ve used in the posts which

# ASPInsiders said on Thursday, October 29, 2009 6:38 AM

Yesterday I’ve ended up receiving an interesting question regarding the code I’ve used in the posts which

# luisabreu said on Thursday, October 29, 2009 9:13 AM

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

# william apken said on Thursday, October 29, 2009 9:48 AM

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

If you put a table into the html section it works.

The code below works:

<table >

                   <thead>

                     <tr>

                       <td>Name</td>

                       <td>Address</td>

                     </tr>

                   </thead>

                   <tbody id="view" class="sys-template">

                  <tr><td>{{FirstName}}</td><td>{{LastName}}</td></tr>

                   </tbody>    

                 </table>

If the template includes <ul><li> this works fine.

The code below is what makes it break.

var editHtml = "<tr><td>{{City}}</td><td>{{State}}</td><td>{{Zip}}</td></tr>";

# william apken said on Thursday, October 29, 2009 12:32 PM

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

I changed the <tr><td> code to just list the bindings.

{{FirstName}}{{LastName}}. It still breaks in the function listed below:

function Sys$UI$Template$recompile() {

       /// <summary locid="M:J#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 $context.data = (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

# luisabreu said on Thursday, October 29, 2009 1:00 PM

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

var tmpl = "<table><tbody><tr><td>{{name}}</td><td>{{address}}</td></tr></tbody></table>";

                         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.

# william apken said on Thursday, October 29, 2009 4:07 PM

That worked.  Thanks.

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above:  

Search

This Blog

Tags

Community

Archives

Syndication

Email Notifications

News




  • View Luis Abreu's profile on LinkedIn


    Follow me at Twitter

    My books

    Silverlight 4.0: Curso Completo

    ASP.NET 4.0: Curso Completo

    Portuguese LINQ book cover

    Portuguese ASP.NET 3.5 book cover

    Portuguese ASP.NET AJAX book cover

    Portuguese ASP.NET AJAX book cover