Ce dépôt est un tutoriel qui explique comment utiliser l'API de son site Kiubi pour créer une navigation dynamique, en chargeant des éléments à la demande.
Bien qu'applicable à tout un ensemble d'éléments, ce tutoriel s'attache plus particulièrement aux listings de produits. Il peut être adapté pour fonctionner par exemple avec les listings de billets du blog ou de commentaires.
La première partie expliquera comment ajouter un lien "charger davantage" au bas d'un widget de liste de produits. Ce lien permettra de naviguer dans la liste des produits sans recharger la page, à l'aide de l'API Front-office.
La deuxième partie est une variante de la première. Cette fois, le chargement de nouveaux produits se fera automatiquement au fur et à mesure que l'internaute va scroller dans la page.
##Prérequis
Ce tutoriel suppose que vous avez un site Kiubi et qu'il est bien configuré :
- l'API est activée
- l'e-commerce est activé
- le site est en thème personnalisé, basé sur Shiroi
Il est préférable d'être à l'aise avec la manipulation des thèmes personnalisés. En cas de besoin, le guide du designer est là.
Ce tutoriel est applicable à tout thème graphique mais les exemples de codes donnés sont optimisés pour un rendu basé sur le thème Shiroi.
L'objectif est d'intégrer un bouton à un widget "Liste de produits" permettant de charger davantage d'éléments au clic et de le masquer lorsqu'il n'y a plus d'élément à afficher.
Pour y arriver, on utilise ici plusieurs composants :
- le framework jQuery pour les manipulations javascript de base
- le client Javascript API Front-office de Kiubi (qui est un plugin jQuery) pour récupérer les produits
- le plugin jQuery loadmore.js qui ajoute la capacité de chargement automatique d'éléments de listing produit, billets de blog, ou encore commentaires produit.
On va créer un modèle de widget spécifique pour faciliter sa mise en place.
Tout d'abord, il faut inclure les fichiers javascript du tutoriel. Le framework jQuery étant inclus de base dans Shiroi, il n'est nécessaire d'inclure que les feuilles de styles et scripts ci-dessous dans le <head>
des templates du thème. Vous trouverez ces templates dans le répertoire /theme/fr/templates/
.
<link rel="stylesheet" href="{racine}/{theme}/{lg}/templates/loadmore.css" />
<script type="text/javascript" src="{cdn}/js/kiubi.api.pfo.jquery-1.0.min.js"></script>
<script type="text/javascript" src="{racine}/{theme}/{lg}/templates/loadmore.min.js"></script>
<script type="text/javascript" src="{racine}/{theme}/{lg}/templates/product.tpl.min.js"></script>
Ajouter les fichiers javascript et CSS du répertoire /theme/fr/templates
de ce dépôt dans le répertoire du même nom de votre thème graphique.
Créer ensuite un nouveau modèle pour le widget "Liste de produits".
Pour cela copier le dossier /theme/fr/widgets/catalogue/liste_produits/button
de ce dépôt au même endroit dans votre thème graphique.
Aller ensuite dans le Back-office du site et placer le widget "Liste de produit" dans la page de votre choix. Editer la configuration du widget et choisir le modèle "button". Mettre le paramètre "Afficher la navigation" à "Oui" et limiter l'affichage à quelques produits.
La page sur le site affiche désormais une liste de produits ainsi qu'un bouton "Charger davantage". Si le bouton ne s'affiche pas, c'est que le widget affiche d'ores et déjà tous les produits du listing. Il suffit alors d'ajouter quelques produits ou de diminuer le nombre de produits à afficher dans la configuration du widget pour remédier à la situation.
Examinons en détail le code HTML du modèle button
du widget "Liste de produits"` :
<script type="text/javascript">
var afficher_navigation = parseInt("{widget_afficher_navigation}");
var current_page = parseInt('{num_page}') - 1;
var page_count = parseInt('{nb_pages}');
Une fois la page générée par le CMS, les balises {widget_afficher_navigation}
{num_page}
{nb_pages}
seront substituées par leur valeur correspondante.
if(afficher_navigation == 1 && page_count > 1 && current_page == 0) {
Cette première condition permet de mettre en place la navigation dynamique uniquement si toutes les conditions suivantes sont satisfaites :
- la configuration du widget autorise la navigation
- le listing actuel comporte plus d'une page
- la page actuellement affichée est bien la première page du listing
Si l'une de ces conditions n'est pas satisfaite, la navigation dynamique n'est pas mise en place
$("#listing_{serial} .nav").hide();
On masque la navigation statique générée par le CMS
var listing = $('#listing_{serial} ul:first').loadmore({
api_endpoint : '/catalog' + ('{widget_categorie_id}' ? '/categories/{widget_categorie_id}' : '') + '/products.json',
api_params : {
'limit' : parseInt("{widget_limit}"),
'sort' : "{widget_order_api}",
'available' : "{widget_dispo}",
'in_stock' : "{widget_stock}",
'extra_fields' : 'price_label,variants,description',
'tags' : "{widget_tags}",
'tags_rule' : ("{widget_tags_logique}" == "et" ? "and" : "or")
},
Ces premières options déterminent les paramètres de la requête API correspondant au listing en cours d'affichage. On récupère la configuration du widget (ordre de tri, limite d'affichage, limitations aux tags, disponibilité du produit, restriction à une catégorie). On récupère ainsi exactement les mêmes produits qui auraient été affichés en utilisant le lien "page suivante" de la navigation classique du widget.
render_item : function(product) {
item.header = (item.header || item.description || "");
if("{widget_resume}" && item.header.length > parseInt("{widget_resume}")) {
item.header = item.header.substr(0,parseInt("{widget_resume}")) + "...";
}
// définition du contexte
var ctx = { // liste des balises Kiubi utiles au rendu du template
'affichage' : "{widget_affichage}"
};
return render_product(product, ctx);
}
});
La méthode render_product
définit la façon dont sera "rendu" un objet product
. Cette méthode, appelée également "template javascript", sera appelée pour chaque nouvel élément avant son ajout au listing existant. Elle peut soit retourner du code HTML, soit un élément DOM.
Un exemple d'implémentation de cette méthode est proposé dans le fichier theme/fr/templates/product.tpl.js
.
Le plugin est désormais instancié. On créé ensuite un bouton "Charger davantage"
var BUTTON = $('<div class="more">')
.append($('<a>', {text: "Charger davantage"}))
.insertAfter("#listing_{serial}");
Un clic sur le lien de cet élément doit charger la page suivante du listing
$('a', BUTTON).click(function(){
listing.getNextPage();
});
Enfin, le bouton est masqué lorsque la dernière page du listing a été affichée
listing.on('loadmore.complete', function(){
BUTTON.hide();
});
}
</script>
Le plugin loadmore.js peut également laisser le contrôle sur la façon dont est ajouté chaque élément au listing de produit.
$('#listing_{serial} ul:first').loadmore({
api_endpoint : "..",
api_params : {..},
ui_button : $("a", BUTTON),
render_item : function(){..},
/**
* @param item correspond à l'objet JSON de l'élément courant
* @param Element correspond à l'élement DOM retourné par la méthode render_item
*/
append_item : function(item, Element) {
Il suffit d'implémenter son propre callback et de la passer en paramètre à l'instanciation du plugin. A noter que dans la méthode append_item, this
correspond à l'objet $('#listing_{serial} ul:first')
:
this.append(item);
console.log("un élément à été ajouté")
})
});
L'instanciation du plugin loadmore.js expose 2 méthodes publiques :
nom | description |
---|---|
getNextPage |
Charge la page suivante et l'ajoute au listing de façon asynchrone et retourne un objet $.Deferred |
hasNextPage |
Vérifie si le listing comporte une page suivante, (nota: la méthode retourne undefined si aucune page n'a jamais été chargé par le plugin loadmore.js) |
var nav = $('#listing_{serial} ul:first').loadmore({
api_endpoint : "..",
api_params : {..},
render_item : function(){..}
});
nav.getNextPage().done(function()
{
// Une page a été chargée
if(nav.hasNextPage() === false)
{
// Tous les éléments ont été chargée
}
})
Le plugin loadmore.js lance 3 types d'événements.
nom | description | arguments |
---|---|---|
loadmore.append_item |
Cet événement est déclenché immédiatement après qu'un élément ait été ajouté au listing | item , Element |
loadmore.append_page |
Cet événement est déclenché après que le dernier élément de la page en cours ait été ajouté au listing | |
loadmore.complete |
Cet événement est déclenché lorsque tous les éléments du listing ont été chargés et ajoutés. Il n'y a plus d'autre page à afficher |
Les events-handlers sont ensuite attachés au listing à l'aide de la méthode jQuery.on()
$("#listing_{serial} ul:first")
.on('loadmore.append_item', function(e, product, Element){
console.info('Le produit %s a été ajouté', product.name);
})
.on('loadmore.append_page', function(){
console.info('Une page a été chargée');
})
.on('loadmore.complete', function(){
console.info('Tous les éléments ont été chargée');
});
Nous allons utiliser un autre plugin de ce dépôt : infinite_scroll.js tout en gardant les même bases. Les produits ne vont plus être chargés par un clic sur un bouton mais en scrollant vers le bas de la page.
Pour y arriver, on utilise ici plusieurs composants :
- le framework jQuery pour les manipulations javascript de base
- le client Javascript API Front-office de Kiubi (qui est un plugin jQuery) pour récupérer les produits
- le plugin jQuery loadmore.js qui ajoute la capacité de chargement automatique d'éléments de listing produit, billet de blog, ou encore commentaires produit.
- le plugin jQuery infinite_scroll.js qui ajoute la capacité de chargement au scroll de l'internaute.
On va également créer un modèle de widget spécifique pour faciliter sa mise en place.
Il n'est nécessaire d'inclure un script supplémentaire dans le <head>
des templates du thème. Vous trouverez ces templates dans le répertoire /theme/fr/templates/
<script type="text/javascript" src="{racine}/{theme}/{lg}/templates/infinite_scroll.min.js"></script>
Créer ensuite un nouveau modèle pour le widget "Liste de produits".
Pour cela copier le dossier /theme/fr/widgets/catalogue/liste_produits/infinite_scroll
de ce dépôt au même endroit dans votre thème graphique.
Aller ensuite dans le Back-office du site et placer le widget "Liste de produit" dans la page de votre choix. Editer la configuration du widget et choisir le modèle "infinite_scroll". Mettre le paramètre "Afficher la navigation" à "Oui" et limiter l'affichage à quelques produits.
La page sur le site affiche désormais une liste de produits. Au fur et à mesure qu'on se rapproche du bas de la page, les produits sont ajoutés au listing.
Ce plugin supporte les paramètres avancés, les méthodes publiques ainsi que les événements du plugin loadmore.js dont il dépend.
Le plugin infinite_scroll.js permet également de contrôler un seuil, exprimé en pixels, à partir duquel la page suivante est intégrée au listing.
Ce seuil est renseigné à l'instanciation du plugin infinite_scroll.js à l'aide du paramètre threshold
. Il accepte une valeur entière non-signée.
$('#listing_{serial} ul:first').loadmore({
api_endpoint : "..",
api_params : {..},
ui_button : $("a", BUTTON),
render_item : function(){..},
threshold : 100, // 100 pixels avant la fin du listing, on charge les éléments suivants.
});
Sa valeur par défaut est de 0. Les éléments sont donc chargés lorsque le bas de la fenêtre correspond au bas du listing.
L'exemple suivant s'applique à un listing de produits dans un widget liste_produits
. Le code HTML décrit ci-dessous est à intégrer dans le template index.html
du widget liste_produits
.
<link rel="stylesheet" href="{racine}/{theme}/{lg}/templates/loadmore.css" />
<script type="text/javascript" src="{cdn}/js/kiubi.api.pfo.jquery-1.0.min.js"></script>
<script type="text/javascript" src="{racine}/{theme}/{lg}/templates/loadmore.js"></script>
<script type="text/javascript" src="{racine}/{theme}/{lg}/templates/infinite_scroll.js"></script>
<script type="text/javascript" src="{racine}/{theme}/{lg}/templates/product.tpl.min.js"></script>
<script type="text/javascript">
var afficher_navigation = parseInt("{widget_afficher_navigation}");
var current_page = parseInt('{num_page}') - 1;
var page_count = parseInt('{nb_pages}');
if(afficher_navigation == 1 && page_count > 1 && current_page == 0) {
// si la configuration du widget active la navigation, et
// si le listing actuel comporte plus d'une seule page, et enfin
// si la page actuelle est la première page du listing, alors
// on met en place la pagination dynamique
jQuery(function($){
$("#listing_{serial} .nav").hide();
$('#listing_{serial} ul:first').infinite_scroll({
api_endpoint : '/catalog' + ('{widget_categorie_id}' ? '/categories/{widget_categorie_id}' : '') + '/products.json',
api_params : {
'limit' : parseInt("{widget_limit}"),
'sort' : "{widget_order_api}",
'available' : "{widget_dispo}",
'in_stock' : "{widget_stock}",
'extra_fields' : 'price_label,variants,description',
'tags' : "{widget_tags}",
'tags_rule' : ("{widget_tags_logique}" == "et" ? "and" : "or")
},
threshold : 50, // seuil en px par rapport au bas du listing
render_item : function(item) {
item.header = (item.header || item.description || "");
if("{widget_resume}" && item.header.length > parseInt("{widget_resume}")) {
item.header = item.header.substr(0,parseInt("{widget_resume}")) + "...";
}
var ctx = {
'affichage' : "{widget_affichage}"
};
return render_product(item, ctx);
}
});
});
}
</script>