Un AutoComplete avec Rx pour Javascript!
Ça fait déjà quelque fois que je parle de Reactive Extensions. Mais savez-vous qu’il existe également une version pour Javascript qui est à peu près aussi versatile que l’originale ? Bien sûr, par originale, je fais référence à la version .NET. Mais la version Javascript provient également de Microsoft et est maintenue par la même équipe !
Tout d’abord, sachez que vous pouvez obtenir Rx pour Javascript (aussi appelé rxjs) via Nuget. Pour ce faire, vous pouvez simplement demander le package « RxJS-All » qui contient les dépendances vers les principales librairies de Reactive Extensions.
Ce qui est bien, c’est qu’il s’agit d’une librairie qui n’a que très peu d’impact sur votre code existant. Il s’intègre plutôt bien.
La page HTML
Partons d’une simple page HTML très simple qui contient un champ pour taper du texte et un autre pour y afficher un résultat :
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> Type something: <input type="text" id="txtbox" /> <br/> <textarea id="resultArea" rows="12" cols="50"></textarea> </body> </html>
Ensuite, la logique
La logique de l’auto-complete que je veux faire est la suivante :
- La recherche n’est déclenchée que lorsque ça fait au moins 375 milisecondes que l’utilisateur n’a rien tapé.
- N’est déclenché que lorsqu’il y a au moins 2 caractères des tapés.
- Si des résultats ont déjà été affichés et que le texte tombe à moins de 2 caractères, on efface le résultat.
- Un indicateur « loading » pendant le chargement des données.
- Advenant le cas où une recherche est déclenchée alors qu’un autre recherche précédente n’a toujours pas aboutie, cette dernière doit être annulée.
Les dépendances
Avant de continuer, je tiens à précider que j’ai du ajouter les dépendances suivantes depuis Nuget :
- RxJS-Bridges-HTML : Permet de faire le pont entre le DOM et Reactive Extensions de manière « fluent ».
- RxJS-Bridges-jQuery : Permet d’ajouter un pont supplémentaire pour une utilisation harmonieuse de RxJS avec jQuery. On peut alors faire des appels comme $.ajaxAsObservable().
<!-- Framework jQuery --> <script src="Scripts/jquery-1.8.2.js"></script> <!-- Librairie "rxjs" de base --> <script src="Scripts/rx.min.js"></script> <!-- Librairie supplémentaire pour les schedulers (utilisés par rx.html) --> <script src="Scripts/rx.time.min.js"></script> <!-- Bridge DOM & Rx --> <script src="Scripts/rx.html.min.js"></script> <!-- Bridge avec jQuery --> <script src="Scripts/rx.jquery.min.js"></script>
La logique de l’auto-complete
La totalité du script nécessaire pour faire le auto-complete est dans le code suivant : (notez que je n’ai pas fait la logique permettant de sélectionner une valeur, je me contente d’afficher la liste des valeurs retournées par l’api de twitter)
// Résolution des contrôles var txtbox = $("#txtbox"); var resultArea = $("#resultArea"); // Source de données des changements au champ de saisie var textChanged = txtbox .keyupAsObservable() .select(function () { return txtbox.val(); }); // "helpers" pour effacer les résultats et afficher un chargement var showLoading = function () { resultArea.val("-loading-"); }; var clearResult = function() { resultArea.val(""); }; // Logique de l'auto-complete var subscription = textChanged // Attente de 375ms .throttle(375) // Effacer les résultats (dans tous les cas) .doAction(clearResult) // On ne fait rien d'autre si pas au moins 2 caractères .where(function(txt) { return txt.length > 2; }) // On affiche le "loading" .doAction(showLoading) // Souscription à la requête API .selectMany( function(txt) { // Création d'une requête API observable (RxJS-Bridges-jQuery) return $ .ajaxAsObservable({ url: "http://search.twitter.com/search.json", data: { q: txt }, dataType: "jsonp" }) // Si usager tape quelque chose, on discarte le résultat .takeUntil(textChanged); }) // On a des résultats à présenter, alors on efface à nouveau .doAction(clearResult) // Conversion du "payload" résultant en observable de résultat .selectMany(function(response) { return Rx.Observable.fromArray(response.data.results); }) // Création de chaque ligne de présentation pour chaque résultat .select(function(tweet) { return "[" + tweet.from_user_name + "] " + tweet.text; }) // Finalement, on prend chaque résultat formatté et on l'ajoute dans la page .subscribe( function(line) { resultArea.val(resultArea.val() + line + "\n"); });
Comme vous pouvez voir ci-haut, il y a plus de commentaires que de code!
Laisser un commentaire