Knockout JS
Magento 2 utilise Knockout JS comme framework javascript principal, nous allons voir comment l'utiliser. Nous l'appelerons KO dans la suite de la formation.
Bind de base
KO utilise l'attribut data-bind pour associer une valeur à une balise HTML.
Il est par exemple possible de faire
<span data-bind="text: myVariable"></span>
où myVariable est une variable définie par le JS associé à ce template.
Le fichier requirejs-config.js
Magento 2 utilise RequireJS afin d'inclure les fichiers javascript. Cela présente l'avantage de n'inclure un fichier que s'il est appelé dans la page, et de ne l'inclure qu'une fois s'il est appelé plusieurs fois dans une même page.
Nous allons améliorer notre formulaire de demande de devis pour ajouter un bouton permettant de savoir qui est le conseiller commercial associé à notre demande. Pour cela, utilisons l'API https://randomuser.me/api/ afin de générer une personne différente à chaque fois.
Nous allons dans un premier temps pouvoir ajouter un fichier JS grâce au fichier de configuration requirejs-config.js. Ce fichier doit être placé dans le dossier view/frontend.
Exemple de fichier :
var config = {
map: {
'*': {
seller: 'Adexos_Formation/js/seller',
}
}
};
Cette syntaxe indique que nous déclarons un fichier ayant pour alias seller, et qu'il se trouve dans app/code/Adexos/Formation/view/frontend/web/js/seller.js. Nous pouvons remarquer qu'il n'est pas nécessaire de spécifier le chemin view/frontend/web ou l'extension .js.
Attention à bien regénérer les fichiers statiques lors de la modification d'un fichier JS avec la commande
rm -rf pub/static/* && php bin/magento s:s:d -f -a frontend -t Adexos/formation
Une fois notre fichier JS déclaré, nous allons pouvoir l'inclure dans notre template.
Nous avons plusieurs solutions, en fonction de ce que nous voulons faire :
1. Ajout d'un fichier JS simple
Cette méthode permet d'inclure un fichier JS dans la page, sans faire d'action supplémentaire. Le fichier JS sera inclus et interprété. Cela sert en général pour les librairies ou pour des scripts que nous voudrions appeler.
Fichier JS
console.log('Seller file included');
HTML (le template du formulaire de demande de devis)
<script>
require([
'jquery'
'seller',
'domReady!'
], function ($) {
console.log('Seller is ready');
});
</script>
2. Ajout sur un élément du DOM
Cette méthode est utilisée lorsque le fichier JS est un widget au sens jQuery du terme.
Un widget peut avoir des options et appelle la fonction _create quand il est initialisé.
Fichier JS
define([
'jquery',
'jquery/ui'
], function ($) {
'use strict';
$.widget('formation.seller', {
_create: function () {
console.log('Seller widget initialized');
}
});
return $.formation.seller;
});
HTML
<span data-mage-init='{"seller":{}'></span>
ou
<span id="seller_container"></span>
<script type="text/x-magento-init">
{
"#seller_container": {
"seller": {}
}
}
</script>
Les deux syntaxes sont équivalentes et permettent de lier un élément du DOM à notre widget. Cet élément est récupérable dans le widget via this.element, c'est un élément jQuery.
Par exemple : Fichier JS
define([
'jquery',
'jquery/ui'
], function ($) {
'use strict';
$.widget('formation.seller', {
_create: function () {
console.log(this.element.text());
}
});
return $.formation.seller;
});
HTML
<span id="seller_container">My element text</span>
<script type="text/x-magento-init">
{
"#seller_container": {
"seller": {}
}
}
</script>
Passer des options à un widget
Dans un widget, il est possible de récupérer les options via this.options. Les options sont passées dans le JSON lors de l'appel au fichier JS :
Fichier JS
define([
'jquery',
'jquery/ui'
], function ($) {
'use strict';
$.widget('formation.seller', {
_create: function () {
console.log(this.options.myOption);
}
});
return $.formation.seller;
});
HTML
<span id="seller_container">My element text</span>
<script type="text/x-magento-init">
{
"#seller_container": {
"seller": {"myOption": "This is my option"}
}
}
</script>
Les options peuvent être initialisée ou avoir une valeur par défaut comme ceci :
define([
'jquery',
'jquery/ui'
], function ($) {
'use strict';
$.widget('formation.seller', {
options: {
myDefaultOption: 'default value'
},
_create: function () {
console.log(this.options.myOption);
console.log(this.options.myDefaultOption);
}
});
return $.formation.seller;
});
TP - Création d'un bouton indiquant qui est le commercial
Au clic sur un bouton à côté du formulaire, appeler l'API randomuser pour aller chercher une personne aléatoirement.
Exemple de résolution HTML
<button id="seller_button">Check who is your seller</button>
<div id="sellerInfo"></div>
<script type="text/x-magento-init">
{
"#seller_button": {
"seller": {}
}
}
</script>
define([
'jquery',
'jquery/ui'
], function ($) {
'use strict';
$.widget('formation.seller', {
options: {
responseContainer: '#sellerInfo'
},
_create: function () {
this.element.on('click', $.proxy(function () {
const responseContainerElement = $(this.options.responseContainer);
$.ajax({
url: 'https://randomuser.me/api/',
dataType: 'json',
}).done(function (data) {
responseContainerElement.text(data.results[0].name.first + ' ' + data.results[0].name.last);
});
}, this));
}
});
return $.formation.seller;
});
Utilisation des components
Déclarons maintenant un component :
Fichier Adexos/Formation/web/js/mycomponent.js :
define([
'jquery',
'uiComponent',
'ko'
], function ($, Component, ko) {
'use strict';
return Component.extend({
defaults: {
template: 'Adexos_Formation/mycomponent'
},
initialize: function () {
this._super();
this.myText = 'This is my text';
}
});
}
);
Ainsi que le template associé, qui sera situé dans Adexos/Formation/web/template/mycomponent.html.
<span data-bind="text: myText"></span>
Enfin, indiquons à notre phtml d'inclure ce component :
<div id="mycomponent-container" data-bind="scope:'mycomponent'">
<!-- ko template: getTemplate() --><!-- /ko -->
<script type="text/x-magento-init">
{
"#mycomponent-container": {
"Magento_Ui/js/core/app": {
"components": {
"mycomponent": {
"component": "Adexos_Formation/js/mycomponent"
}
}
}
}
}
</script>
</div>
Après déploiement des fichiers statiques, notre template KO affiche bien la valeur de la variable myText.