[jQuery] Consommer un service Astoria avec jQuery

jQuery est un framework JavaScript open source (GNU/GPL) qui sera intégré de base dans Visual Studio 2010.
Ce fut l’occasion pour moi de m’y pencher à l’aide des articles de Davy Pallu.
La communauté autour de jQuery est assez impressionante, d’autant plus que cette technologie est entierement orientée plug in. Léger, cross-browsers et facile d’utilisation, jQuery a su me séduire en remplacement de mes vieux scripts JavaScript.
Pour l’installer il vous suffit d’ajouter à votre projet web actuel le fichier vsdoc de jQuery. Celui ci est téléchargeable sur jquery.com.
La version actuel est la 1.3.2 et le plug in de production fait la taille de 19ko.
Dans cet article, je vais utiliser jQuery pour l’interface graphique mais également pour mes requêtes AJAX afin d’exploiter ADO.NET Data Services (Astoria) qui fournit une serialisation JSON.
Pour plus d’information sur la création du service type Astoria, référez vous à ce billet.
Pour les sources de ce projet, vous les trouverez ici.
Après avoir créé mon service Astoria et ma base de données contenant une table Clients et SecteurActivites je commence le jQuery:
Création du menu
Le menu en jQuery doit proposer la liste des tables proposées par le service. Dans un premier temps je vais concevoir le script jQuery afin d’avoir un semblant de menu animé.
Le css du menu (Menu.css):
1: body{
2: font-family:"Lucida Grande", arial, sans-serif;
3: }
4: li{
5: width:100px;
6: height:50px;
7: color:#191919;
8: text-align:right;
9: cursor:pointer;
10: overflow:hidden;
11: background:#0292C0;
12: }
13: a{
14: color:#FFF;
15: text-decoration:none;
16: }
17: .subtext{
18: padding-top:2px;
19: }
Le fichier javascript Menu.js en jQuery:
1: $(document).ready(function() {
2: $("li").hover(function() {
3: $(this).stop().animate(
4: { width: '150px'
5: },
6: {
7: duration: 400,
8: easing: 'easeOutBounce'
9: })
10: },
11: function() {
12: $(this).stop().animate(
13: { width: '100px' },
14: {
15: duration: 400,
16: easing: 'easeOutBounce'
17: })
18: })
19: });
La méthode ready() correspond en quelque sorte au PageLoad de mon document. J’utilise alors la méthode hover() qui permet de gérer le mouse enter / leave.
Dès que la souris survole un élément de type “li” je modifie sa taille en utilisant l’easing.
L’easing rendra mon animation plus “vivante” et moins linéaire. L’utilisation de l’easing passe par l’ajout d’un plugin appelé jquery.easing.1.3.js et téléchargeable ici.
Au niveau du fichier html j’ajoute les références aux fichiers JS et CSS:
1: <link type="text/css" rel="stylesheet" href="Menu.css"/>
2: <script src="jquery-1.3.2.js" type="text/javascript" />
3: <script src="jquery.easing.1.3.js" type="text/javascript" />
4: <script src="Menu.js" type="text/javascript" />
Et j’ajoute des données en dur pour voir le résultat de mon menu:
1: <ul>
2: <li>
3: <p><a href="#">Table 1</a></p>
4: </li>
5: <li>
6: <p><a href="#">Table 2</a></p>
7: </li>
8: </ul>

Il me faut maintenant me connecter au service Astoria et génèrer dynamiquement le menu.
Pour cela je mets en place l’utilisation de la sérialisation JSON avec les méthodes AJAX intégrées dans jQuery:
1: <script type="text/javascript">
2: function displayTable(table) {
3: $("#ul_tables")
4: .append("<li><p><a href=\"#\">"
5: + table + "</a></p></li>");
6: }
7:
8: function getTables() {
9: $.ajax({
10: type: "GET",
11: url: "WebDataService.svc",
12: data: "{}",
13: contentType: "application/json; charset=utf-8",
14: dataType: "json",
15: success: function(data) {
16: for (var i in data.d) {
17: for (var n in data.d[i]) {
18: displayTable(data.d[i][n]);
19: }
20: }
21: },
22: error: function(xhr) {
23: alert(xhr.responseText);
24: }
25: });
26:
27: return false;
28: }
29: </script>
et je crée un bouton HTML qui chargera mon menu:
1: <button onclick="return getTables();">Get Tables</button>
L’un des inconvénients de cette solution est que mon menu est certes bien rempli avec les tables mais jQuery ne capte pas la méthode “hover” puisqu’il a été modifié à la volée.
Pour cela, il existe la méthode live() qui saura prendre en compte les ajouts d’éléments dans mon menu.
Menu.js devient comme ceci:
1: $(document).ready(function() {
2: $("li").live("mouseover", function() {
3: $(this).stop().animate(
4: { width: '150px'
5: },
6: {
7: duration: 400,
8: easing: 'easeOutBounce'
9: });
10: })
11:
12: $("li").live("mouseout", function() {
13: $(this).stop().animate(
14: { width: '100px'
15: },
16: {
17: duration: 400,
18: easing: 'easeOutBounce'
19: });
20: })
21: });
Nous pouvons agrémenter notre solution d’une progressbar se déclenchant pendant que la requête AJAX s’effectue.
Après avoir généré un GIF sur http://www.ajaxload.info, je m’abonne aux événements ajaxStart et ajaxStop de mon document.
J’utilise le plug in SimpleModal disponible ici.
1: $(document).ajaxStart(function() {
2: $.modal("<div><img src=\"Images/ajax-loader.gif\" /></div>",
3: { onOpen: function(dialog) {
4: dialog.overlay.fadeIn('fast', function() {
5: dialog.data.hide();
6: dialog.container.fadeIn('fast', function() {
7: dialog.data.slideDown('fast');
8: });
9: });
10: }
11: });
12: });
13: $(document).ajaxStop(function() {
14: $.modal.close();
15: });
Affichage des données contenus dans les tables
L’affichage du contenu d’une table se fera à l’aide d’une modal popup. Pour changer de technique, je mettrai en application le plug in jQueryUI.
jQueryUI est un peu l’Ajax Control Toolkit des développeurs ASP.NET. Il fournit de nombreux effets, thèmes, contrôles réutilisable…
Après l’avoir téléchargé sur le site officiel www.jqueryui.com j’ajoute à ma page les liens vers les CSS et fichiers javascripts:
1: <link type="text/css" href="css/ui-lightness/jquery-ui-1.7.2.custom.css"
2: rel="stylesheet" />
3: <script src="Scripts/jquery-ui-1.7.2.custom.min.js" type="text/javascript" />
Le skin par défaut de jQueryUI est orange, j’en profite pour modifier Menu.css afin d’avoir une IHM globalement orange (et moche :))
Je capture le clic sur mon menu et appel la méthode getTable qui se chargera d’afficher les données:
1: $("li").live("click", function($e) {
2: $e.preventDefault();
3: return getTable($(this).attr("href"));
4: })
La méthode getTable se connecte grâce à l’AJAX à mon service pour lire les données au format JSON.
1: function getTable($tableName) {
2: $.ajax({
3: type: "GET",
4: url: "WebDataService.svc/" + $tableName,
5: data: "{}",
6: contentType: "application/json; charset=utf-8",
7: dataType: "json",
8: success: function(data) {
9: for (var i in data.d) {
10: for (var n in data.d[i]) {
11: //Mise à jours des données içi
12: }
13: }
14: $("#dialog").dialog('open');
15: },
16: error: function(xhr) {
17: alert(xhr.responseText);
18: }
19: });
20:
21: return false;
22: }
Voici le résultat:
Il me manque l’implémentation de l’affichage des données. Le problème est que nous recevons bien les données mais il nous faut d’abord afficher le nom des colonnes.
Le nom des colonnes sont représentées par des propriétés de l’objet créée à la volé:
Pour cela je vais utiliser la réflexion comme en C#.
function GetProperties(obj) {
var props = new Array();
for (var s in obj) {
if (typeof (obj[s]) != "function") {
props[props.length] = s;
}
}
return props;
};
function getTable($tableName) {
$.ajax({
type: "GET",
url: "http://localhost:2935/WebDataService.svc/"
+ $tableName,
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
var corp = "<tbody>";
for (var i in data.d) {
corp += "<tr>";
//Si c'est la première boucle -> Récupération des noms de colonnes par reflexion
if (i == 0) {
var entete = "<thead><tr class=\"ui-widget-header\">";
var props = GetProperties(data.d[i]);
for (var z in props) {
entete += "<th>" + props[z] + "</th>";
//Value: data.d[i][props[i]]
}
entete += "</tr></thead>";
$("#tables").append(entete);
}
for (var n in data.d[i]) {
//Mise à jours des données içi
corp += "<td>";
corp += data.d[i][n];
corp += "</td>";
}
corp += "</tr>";
}
corp += "<tbody>";
$("#tables").append(corp);
$("#dialog").dialog('open');
},
error: function(xhr) {
alert(xhr.responseText);
}
});
return false;
}
Résultat:
Pour le reste des opérations (CRUD) il suffit de modifier le type de la requête (Par exemple POST ou DELETE) à ce niveau:
$.ajax({
type: "GET",
url: "http://localhost:2935/WebDataService.svc",
data: "{}",
contentType: "application/json; charset=utf-8",