[Build 14] – IE11’s developer tools just got nicer

Mail de Mehdi
Samedi 5 avril 2014 11:00
IE11’s developer tools just got nicer 
Speaker : Andy Sterland
On commence directement par une démo.

Nouveautés : on a un maintenant un bouton step qui nous permet de faire un step et ne debugger que notre code sans accéder aux bibliothèques (jquery par exemple) cette fonction est configurable par défaut sur les fichiers mimifé, sinon on peut choisir les fichiers js qu’on définit comme librairie ou pas.

Maintenant nous avons la possibilité de faire un break dans les exceptions déclenchées par notre code et d’ignorer les exceptions des librairies.

Le debug des fichiers type script fonctionne !!! Plus besoin de passer le code JavaScript généré ! Il existe un bouton pour faire le passage entre les fichiers TS et les fichiers JS.

Le debugger garde maintenant les paramètres même si on ferme la page courante !
(exemple : plusieurs points d’arrêts dans un fichier JS => on ferme notre page => on la ré ouvre => on ouvre le debugger avec F12, nos breaks points sont toujours là !)

Avec console.log on peut inspecter un objet maintenant !

Les erreurs peuvent être enregistrées même avant l’ouverture de la console.

Nouvelle commande dans la console « $_ » pour récupérer la dernière expression.

On passe au dom explorer : Nouveauté : on a des indicateurs avec des couleurs pour les changements dans les css (orange = modifier, rouge = supprimer, vert= nouvelle)

On un onglet « changes » qui rassemble aussi les changements des css qu’on a appliqué en live ! Le copier-coller des valeurs dans cet onglet permet de recopier les bonnes valeurs = ce qui est modifié est gardé ce qui est supprimé est effectivement supprimé dans le copier (cool !)

Maintenant on peut forcer le mode hover et visited dans le dom !

On passe rapidement sur WP, une seule info à retenir, on a accès aux mêmes options de debug.
Mehdi

[Build 14] – Strategies for developing Cross-Device applications with Visual Studio 2013

Mail de John
Vendredi 4 avril 2014 06:09

Strategies for developing Cross-Device applications with Visual Studio 2013

 

Retour sur les choix inhérents au développement Cross Platform.

Doit-on choisir le développement natif ou le développement utilisant des technologies web ?
C’est la réponse que cherche à apporter cette session.
Natif : Plus grande flexibilité de customisation par device, accès complet au matériel, device dependant
Web : Device independant, facile à gérer mais possibilités d’intégration à la plateforme limitées.

 

Présentation de stratégies pour le développement web :

– Ne rien faire
– S’adapter au niveau du client
o Duplication minimale mais pas de customisation par device et inefficience au niveau de la bande passante
– S’adapter au niveau du serveur
o Flexibilité maximale mais probablement pas mal de duplication de code
– Tenter d’imiter le fonctionnement natif
o La meilleur expérience sur chaque device mais ce n’est toujours pas du natif

Démonstration sur le CSS et les Media Queries, Bootstrap.
Démonstration JQuery Mobile
Démonstration avec Knockout, TypeScript, Cordova.
Développement natif :

– Utiliser les outils de chaque plateforme
o Impose d’apprendre à développement avec divers IDE, langages
o Pas de partage de code
– Utiliser Xamarin
o Applications complètement native
o Utilisation de Visual Studio
o Partage de la logique du code entre chaque plateforme grâce à des PCL
o 100% des APIs de chaque device sont exposées par Xamarin

Démonstration avec Xamarin et MVVMCross (Breakpoints et remote debug Android)
John

[Build 14] – Building a Single Page Application with ASP.NET and AngularJS

Mail de Mehdi
Jeudi 3 avril 2014 16:42

Building a Single Page Application with ASP .NET and AngularJS

// Speakers:
David Catuhe, Jon Galloway

Session un peu décevante, niveau 300 mais plutôt destinée aux personnes n’ayant jamais fait d’AngularJS.

Les démos sont là pour attirer ces gens sur ce framework.

On débute avec la façon avec laquelle on intègre Angular dans une page HTML => nous avons besoin que d’un seul fichier
«angular.min.js»

Trois solutions sont possibles pour ajouter AngularJS à un projet => soit on télécharge les fichiers, soit on utilise NuGet ou un CDN (le plus conseillé par David).
// Début de la démo :

Initialisation du controller de la vue, David ajoute comme injection $scope pour accéder au scope de la vue. Il initialise une variable avec un tableau de deux éléments qui seront bindés dans la vue avec un repeater, il lance la page, et voilà ! ça marche très simplement.

Ensuite on nous introduit les différentes façon d’accéder à de la data, avec $http qui est basé sur une version light de jQuery, et $resource qui est un objet spécifique fait pour du restful api (qui sera utilisé un peu plus tard dans la démo pour interroger le serveur au lieu d’avoir la data en local)

Pour les utiliser depuis le controller, il faut les ajouter dans les injection de dépendance de celui-ci.

On nous présente comment créer un service pour rendre transparent l’accès aux données.

Démo de comment on peut créer un filtre dans un repeater.

Une petite démo du Two-Way Data Binding avec enregistrement en local des données.

Une démo sur les animations (avec le repeater , angular ajoute des classes spécifiques quand un element est ajouter/supprimer/modifier dans la liste et on peut donc facilement faire des animations en css).

Présentation de comment créer des routes dans Angular avec le template de la « page » qui va avec.

Mehdi

La délégation d’évènement avec jQuery

Une fonctionnalité méconnue et pourtant très utile de jQuery est la délégation d’évènement. Elle permet de brancher un gestionnaire d’évènement sur un élément parent de l’élément que l’on veut réellement écouter.

Pas assez clair? Pour mieux comprendre faisons d’abord un petit rappel.

La notion de « bulle »

Lorsque l’on clique sur un élément du DOM, l’évènement « click » est déclenché sur le nœud en question, puis est propagé sur tous ses nœuds parents jusqu’à remonter sur l’élément racine du document, c’est-à-dire « body ».

Dans l’exemple suivant, si vous cliquez sur le bouton, l’évènement « click » sera d’abord déclenché sur le <button>, puis sur la <div>, puis <article>, <section> et enfin <body>.

<body>
  <section>
    <article>
      <div>
        <button></button>
      </div>
    </article>
  </section>
</body>

Cette remontée du DOM aura lieu que vous traitiez ou non l’évènement à quelque niveau que ce soit – bien qu’il soit possible de bloquer la bulle, mais c’est un autre sujet. Il est donc possible d’intercepter l’évènement à plusieurs reprises en branchant des gestionnaires d’évènement à différents niveaux.

$(document).ready(function () {
  $("article").on("click", function (e) {
	// Gestionnaire d'évènement sur <article>
  });
  
  $("button").on("click", function (e) {
	// Gestionnaire d'évènement sur <button>
  });
});

Dans ce dernier exemple, on branche deux gestionnaires d’évènement, un sur <button> et un sur <article>. Si l’on clique sur le bouton, le gestionnaire d’évènement branché sur <button> sera déclenché en premier, puis suite à la remontée de la bulle le long du DOM, ce sera le tour de celui qui est branché sur <article>. On voit que l’ordre dans lequel ils ont été abonnés importe peu.

Comment mettre en place la délégation

La méthode on() de jQuery permet d’indiquer un paramètre supplémentaire : un sélecteur désignant les nœuds enfants que l’on souhaite écouter. Dans ce cas, le gestionnaire branché sera déclenché lorsque l’évènement se sera propagé jusqu’à l’élément, mais uniquement si la cible initiale – par exemple l’élément sur lequel on a vraiment cliqué – respecte le sélecteur indiqué en paramètre.

$(document).ready(function () {
  $("article").on("click", "button" /* Sélecteur supplémentaire */, function (e) {
	// Gestionnaire d'évènement sur <article>
	// mais qui ne se déclenchera que si on a cliqué sur <button>
  });
});

C’est donc la présence de ce paramètre supplémentaire qui induit la délégation d’évènement dans jQuery.

Vous avez compris le principe. Voyons maintenant trois cas d’utilisation concrets, issus de mon expérience, qui vous démontreront tout l’intérêt que peut revêtir cette fonctionnalité.

Beaucoup d’éléments à écouter

Imaginez que vous affichiez un tableau HTML sur votre page web, que celui-ci contienne un million de cellules, et que vous souhaitiez brancher un gestionnaire d’évènement pour écouter les clicks sur chacune d’entre elles.

<table id="big-table">
  <tr>
    <!-- Ici plein de cellules -->
    <td></td>
    <td></td>
  </tr>
</table>

Si vous le faites en vous branchant individuellement sur chacune des cellules, vous allez enregistrer un million de gestionnaires d’évènement en mémoire. Inutile de vous dire que ce n’est pas une très bonne idée.

En utilisant la délégation vous pouvez brancher un seul gestionnaire d’évènement au niveau du tableau lui-même. Ce gestionnaire sera alors en mesure de traiter les clicks sur chacune des cellules.

$(document).ready(function () {
  $("#big-table").on("click", "td", function (e) {
	// Gestionnaire d'évènement unique pour l'ensemble des <td>
  });
});

A ce stade, vous devriez commencer à vous poser la question suivante : comment savoir quelle cellule a été clickée?

Pour ce cas de figure, jQuery a tout prévu, et dans l’argument passé en paramètre au gestionnaire d’évènement – appelé « e » dans notre exemple – vous trouverez trois propriétés qui vous permettront d’obtenir des informations.

  • e.target désignera l’élément qui a déclenché initialement l’évènement, c’est-à-dire la cellule.
  • e.currentTarget désignera l’élément sur lequel l’évènement est en train de buller, c’est-à-dire le tableau.
  • e.delegateTarget désignera l’élément sur lequel est branchée la délégation, c’est-à-dire ici encore le tableau.

Notez aussi que le mot-clef this comme e.currentTarget désignera toujours l’élément sur lequel l’évènement est en train de buller, c’est-à-dire celui correspodant au sélecteur que l’on a indiqué en paramètre de la fonction on().

Les fragments de code HTML

Imaginez que vous affichez une liste d’items.

<ul id="list">
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
</ul>

Chacun de ces items peut être supprimé ou ré-ordonné dans la liste par glissé/déposé. Pour ce faire, on branche sur chacun des items des gestionnaires d’évènement chargés de traiter ces opérations.

$(document).ready(function () {
  $("#list .list-item").on("dragstart", function (e) {
	// Gestionnaire d'évènement de glissé/déposé
  });
  
  $("#list .list-item .delete").on("click", function (e) {
	// Gestionnaire d'évènement de suppression des items
  });
});

Une première remarque – inspirée de l’exemple précédent – est qu’il est possible de brancher les gestionnaires d’évènement par délégation sur la liste elle-même. Seulement voilà : cette liste est susceptible à tout moment d’être mise à jour par écrasement, suite par exemple à l’appel d’une requête Ajax.

function refreshList() {
  $.ajax("/UNE-URL-QUELCONQUE").done(function (html) {
  	$("#list").replaceWith(html);
	// Il faut rebrancher tous les gestionnaires d'évènements 😦
  });
}

Le problème, c’est qu’une fois cette opération d’écrasement effectuée, il faut rebrancher tous nos gestionnaires d’évènements car les éléments du DOM auxquels ils étaient rattachés ont été supprimés du document. Notez au passage qu’il est inutile de s’inquiéter du désabonnement de ces gestionnaires d’évènements, jQuery les nettoyant automatiquement lors de l’appel à la méthode replaceWith().

Pour pallier à l’inconvénient d’avoir à tout rebrancher à chaque rafraichissement de la liste, nous allons tout d’abord encadrer celle-ci avec un nouveau parent.

<div id="list-wrapper">
  <ul id="list">
    <!-- Ici les items -->
  </ul>
</div>

Nous allons ensuite brancher nos gestionnaires d’évènements par délégation sur ce nouvel élément.

$(document).ready(function () {
  $("#list-wrapper").on("dragstart", ".list-item", function (e) {
	// Gestionnaire d'évènement de glissé/déposé
  });
  
  $("#list-wrapper").on("click", ".list-item .delete", function (e) {
	// Gestionnaire d'évènement de suppression des items
  });
});

Le résultat de ces changements est que lorsque la liste sera écrasée, l’élément qui l’encadre lui ne le sera pas, et les gestionnaires d’évènements qui sont branchés seront par conséquent bien conservés. Par ailleurs, bien que le contenu de la liste soit mis à jour, ses items respectent toujours le sélecteur indiqué en paramètre de la délégation d’évènement. Comme ce sélecteur n’est appliqué que lorsqu’un évènement est capturé au niveau du délégué, les gestionnaires seront bien déclenchés.

Il est très courant de nos jours de mettre à jour des pans entiers d’une page web avec des appels Ajax, et ce procédé vous permettra de vous simplifier grandement la vie quant à la gestion des évènements sur ces fragments.

Gestion de la propagation d’évènements

Imaginez maintenant que lorsque l’utilisateur clique n’importe où sur la page, il faille escamoter certains morceaux de celle-ci, comme typiquement une popup.

<body>
  <div class="popup">
    <button type="button">Cliquez-moi</button>
  </div>
</body>

Pour cela le plus simple est de brancher un gestionnaire d’évènement au niveau le plus haut de la page, c’est à dire sur <body>.

$(document).ready(function () {
  $("body").on("click", function (e) {
	$(".popup").hide();
  });
});

Cette mécanique fonctionnera parfaitement, excepté qu’elle dissimulera également la popup lorsque l’on clique dans le contenu de celle-ci, par exemple sur le bouton qu’elle contient. Or ce n’est pas ce que nous souhaitons.

Encore une fois nous allons pouvoir utiliser la délégation pour corriger ce problème. Pour cela, nous allons enregistrer un nouveau gestionnaire d’évènement click sur le <body> de la page. Mais attention, nous allons l’enregistrer avant celui que nous avons déjà indiqué. Ce gestionnaire d’évènement agira par délégation sur notre popup.

$(document).ready(function () {
  $("body").on("click", ".popup", function (e) {
    e.stopImmediatePropagation();
  });

  $("body").on("click", function (e) {
	$(".popup").hide();
  });
});

Puisque nous avons branché deux gestionnaires d’évènements sur <body>, lors d’un click sur la page jQuery les traitera tous les deux dans l’ordre où nous les avons indiqué. Mais une différence importante est que le premier ne sera déclenché que lorsque le click aura été propagé depuis la popup ou son contenu. Comme on l’a déjà vu le second gestionnaire d’évènement sera lui déclenché quelque soit l’endroit que l’on cliquera sur la page.

Or dans le premier cas, on empêche la bulle de se propager aux autres gestionnaires d’évènement en utilisant la méthode stopImmediatePropagation(). Ainsi, on inhibe l’exécution de tous les autres gestionnaires d’évènements qui pourraient avoir été branchés sur le même élément – ici <body>.

Le résultat est que si l’on clique sur le bouton, le premier gestionnaire d’évènement sera en mesure de capturer ce click au moment où celui-ci atteindra la popup, et l’empêchera d’être capturé par l’autre gestionnaire d’évènement.

Au passage, si l’on place un point d’arrêt dans le premier gestionnaire d’évènement et que l’on clique sur le bouton, on constate que l’argument qui est passé en paramètre contient les informations suivantes :

  • e.target désigne le <button>.
  • e.currentTarget et this désignent <div class= »popup »>.
  • e.delegateTarget désigne <body>.

Localiser la saisie utilisateur côté client dans ASP.NET MVC 3

Depuis la première version d’ASP.NET MVC, un des composants qui a subi le plus de modifications est sans doute la validation côté client. Au départ Microsoft avait développé sa propre librairie Javascript, avant de se tourner peu à peu vers jQuery, une librairie très populaire qu’ils ont choisi d’intégrer directement à leur solution.

Le contrecoup de ce revirement est que selon qu’une application est basée sur ASP.NET MVC 1, 2 ou 3, la validation côté client peut fonctionner selon des mécanismes assez différents. La localisation de cette validation en particulier peut s’avérer assez délicate à mettre en place.

La localisation de la validation dans ASP.NET MVC 3

Quand on parle de localisation de la validation, on ne fait pas seulement allusion au fait que les messages qui s’affichent soient dans la langue attendue, il s’agit aussi que les informations saisies par l’utilisateur soient validées selon les règles adéquates. Par exemple, que penser d’une application entièrement en français qui refuserait le nombre décimal « 5,5 » parce que celui-ci contient une virgule comme séparateur décimal? Ce n’est probablement pas ce à quoi s’attendraient la plupart des utilisateurs.

Avec ASP.NET MVC 3, parvenir à mettre en place cette localisation est un vrai parcours du combatant. En effet, tout repose maintenant sur le plugin jQuery Validation, qui utilise un système de « règles » pour valider la saisie utilisateur. Les règles fournies par défaut sont adaptées à la culture anglaise, et il faut les surcharger, c’est à dire les remplacer et les adapter, si l’on souhaite que notre application accepte de valider une culture différente.

Ce que fournit jQuery Validation

En standard, jQuery Validation fourni trois autres groupes de règles, pour les cultures allemande, néerlandaise et brésilienne. Mais non seulement celles-ci sont très incomplètes (la néerlandaise et la brésilienne ne surchargent que la règle de validation des dates) mais aucune ne colle à la culture française. Et voici ce que propose le fichier de règle pour la culture allemande :

/*
 * Localized default methods for the jQuery validation plugin.
 * Locale: DE
 */
jQuery.extend(jQuery.validator.methods, {
	date: function(value, element) {
		return this.optional(element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
	},
	number: function(value, element) {
		return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);
	}
});

Les allemands utilisent bien la virgule comme séparateur décimal; en revanche ils utilisent le point comme séparateur de milliers (alors que nous utilisons un espace blanc). Bien sûr il serait facile de recopier le contenu de ce fichier avant de l’adapter, mais ce scénario n’est réaliste que si notre application n’est conçue que pour la langue française. Que faire si cette dernière est multilingue?

La librairie jQuery Globalization

L’intérêt récent de Microsoft pour jQuery les a amené à proposer leurs propres plugins : jQuery DataLink pour la liaison de données, jQuery Templates pour le templating et jQuery Globalization pour la localisation. Jusqu’à il y a peu, ces trois plugins, encore à l’état de béta version, étaient considérés par l’équipe jQuery comme des plugins « officiels ». Ce n’est plus le cas, toutefois les deux premiers plugins ont vu leur existence prolongée par leur créateur, sous la forme de JsRender et JsViews. Ils devraient être à terme inclus dans la librairie jQuery UI. Quand à jQuery Globalization, il était déjà très complet et parfaitement utilisable en production, et c’est heureux puisque nous allons nous en servir pour rendre notre application multilingue.

jQuery Globalization est composé de très nombreux fichiers correspondant à autant de cultures. Ces fichiers exposent les caractéristiques de chacune de ces cultures, ainsi que des fonctions permettant de traduire aussi bien les dates que les nombres décimaux, et bien plus encore.

Pour implémenter ce plugin dans une application web ASP.NET MVC 3, rien de plus simple. Après l’avoir téléchargé et placé dans notre solution, nous devons tout d’abord le référencer :

<script type="text/javascript" src="@Url.Content("~/Scripts/jquery/plugins/glob/jquery.global.js")"></script>

Ensuite nous devons charger dynamiquement le fichier de localisation correspondant à la culture de l’utilisateur, et configurer le plugin pour utiliser celui-ci :

<script type="text/javascript" src="@Url.Content("~/Scripts/jquery/plugins/glob/globinfo/jquery.glob." + Request.UserLanguages[0] + ".js")"></script>
<script type="text/javascript">
    jQuery.global.preferCulture("@Request.UserLanguages.ToCorrectCase()");
</script>

Request.UserLanguages est un tableau permettant d’obtenir côté serveur la liste des cultures configurées (par ordre de préférence) dans le navigateur de l’utilisateur. Vous vous demandez sans doute à quoi sert la fonction ToCorrectCase(). Malheureusement certain navigateurs comme Firefox renvoient « fr-fr » pour la langue française quand ils devraient renvoyer « fr-FR » (notez la différence de casse), et jQuery Globalization est sensible à ce détail; il faut donc s’y adapter et c’est à ça que sert cette fonction.

N’oubliez pas que les fichiers source de jQuery sont disponibles sur le CDN de Microsoft, tout comme de nombreux plugins.

Tout le nécessaire est maintenant en place pour permettre la localisation multilingue de notre application.

Comment relier jQuery Validation et jQuery Globalization

La dernière étape va consister à relier jQueryValidation, qui s’occupe de la mécanique de validation côté client de l’application, à jQuery Globalization, qui s’occupe exclusivement de la localisation.

Pour cela, nous devons faire référencer un nouveau fichier Javascript par notre application, et y ajouter le code suivant :

jQuery.extend(jQuery.validator.methods, {
    date: function (value, element) {
        return this.optional(element) || jQuery.global.parseDate(value) != null;
    },
    number: function (value, element) {
        return this.optional(element) || !isNaN(jQuery.global.parseFloat(value));
    },
    range: function (value, element, param) {
        value = jQuery.global.parseFloat(value);
        return this.optional(element) || (value &gt;= param[0] &amp;&amp; value &lt;= param[1]);
    }
});

Par le biais de ce code nous surchargeons trois règles de validation de jQuery Validation : la validation de la date, des nombres décimaux, et des intervalles. D’autres règles pourraient potentiellement être également surchargées.

Grâce à ce « pont » établi entre les deux plugins, jQuery Validation va maintenant se servir des fonctions de jQuery Globalization pour valider la saisie de l’utilisateur. Supposons que celui-ci doive indiquer quel sera le pourcentage de TVA sur un produit quelconque. La propriété correspondante dans le modèle de la vue ressemblerait à ceci :

/// <summary>
/// TVA applicable sur le produit
/// </summary>
[Range(0.0, 100.0)]
public double TVA { get; set; }

Notez que la règle de validation de nombre décimal est implicite dès lors qu’il s’agit d’un type « double » (nombre décimal à double précision).

Maintenant si par exemple l’utilisateur a son navigateur configuré dans la culture française, et qu’il saisit « 5,5 », nous serons en mesure de valider que ce nombre est dans un format décimal correct, et qu’il est compris dans une intervalle allant de 0 à 100. Notre application web est donc bien multilingue.