====== JavaScript ====== Quelques points clés de mes apprentissages, notamment sur https://grafikart.fr/formations/formation-javascript ===== Les variables & Co ===== Un peu comme en Python, tout est objet en JS !\\ Si on déclare une simple variable : //let a = 3//\\ puis que l'on fait //typeof(a)//, ça nous retourne //number//\\ et si on tape //Number//, on voit : //function Number()// qui contient un prototype //Number// … qui contient un //// **Object** …CQFD on n'utilise plus pour déclarer une variable le mot-clé var\\ on privilégie **const** et **let**\\ Pour les types de base (int, float, string), const définit une constante… si on essaie de modifier… //invalid assignment to const…//\\ En revanche pour les objets tableau, structure (JSON)… on peut modifier !\\ On peut donc privilégier **const** par défaut. Définir une chaîne à partir de plusieurs variables : ma_chaine = 'le résultat est : ' + ma_var1 + ' ' + ma_var2 // devient avec les back-ticks : ma_chaine = `le résultat est : ${ma_var1} ${ma_var2}` ===== Les fonctions fléchées (arrow function) ===== https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Functions/Arrow_functions Notamment lors des callbacks et retour de promesses, on écrira souvent : à la place de input_sig.addEventListener('input', function (event) { //code de la fct }) cf. plus bas dans [[#ecouteur_d_evenement_addeventlistener|l'exemple sur l'écouteur d’événement]] ===== Côté navigateur ===== Les navigateurs intègrent un interpréteur, dans le principe, il n'y a donc rien à installer pour tester du code JS (notamment via la console du débugueur),\\ ceci dit, une sécurité (https://developer.mozilla.org/fr/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp) empêche d'appeler un fichier js dans un fichier html, même s'il est dans le même répertoire, donc le code : ne fonctionne pas !\\ On écrira donc : … … et comme expliqué dans le commentaire dans le code ci-dessus, pour disposer d'un serveur http minimaliste, on lancera python3 -m http.server (port 8000 par défaut) ou python3 -m http.server 8001 pour le lancer sur le port 8001 dans la déclaration script ci-dessus pour inclure le fichier app.js dans mon code html, est utilisé //type="module"//. Cela inclue **defer** qui permet de charger le code mais de différer son exécution à la fin du chargement de la page html et d'éviter ainsi de mettre la ligne en fin du fichier html ! Cela permet aussi d'utiliser les **import** JS ===== DOM ===== Un objet **window** (par défaut, la variable //this// pointe aussi dessus) permet d'accéder à l'objet global de la fenêtre qui contient en premier lieu le sous-objet **document** **Convention** : pour les méthodes de //window//, on les appellera sans préfixer avec window., exemple : au lieu de //window.addEvenListener()//, on écrira simplement //addEventListener()//\\ en revanche pour les variables, on garder //window.// devant… sauf pour //document// ===== querySelector et querySelectorAll ===== C'est la méthode de //document// qui permet de sélectionner les différents éléments que l'on souhaite manipuler. Comme illustrer dans la [[https://developer.mozilla.org/fr/docs/Web/API/Document/querySelector|doc MDN]], on peut écrire :
et accéder à l'entrée (input) par le code JS : const input_sig = document.querySelector("div.sig-input input[name='location']") un peu verbeux mais ça a le mérite d'être clair, notamment pour un futur relecteur !\\ autre exemple similaire : l’input qui a pour name='sample-id' dans le formulaire qui a pour id='provenance-form' : const sample_id = document.querySelector("#provenance-form input[name='sample-id']") Avec //querySelectorAll//, on peut sélectionner un ensemble d'éléments, comme les boutons des sous-formulaires d'un formulaire complexe. le sélecteur est une chaîne de caractère : * sans préfixe pour correspondre aux //name//, * précédé de # pour les //id//, * précédé de //.// pour les classes si on fait dans la console un const madiv = document.querySelector('.ma-classe')ça retourne //undefined//, il faut bien taper madiv pour voir le contenu de la variable ! ===== Écouteur d'événement (addEventListener) ===== C'est un des intérêts d'ajouter du JS à une page… écouter un ou des événements pour inter-agir avec la page, tantôt faire de l'autocomplétion, tantôt ajouter un autre formulaire, ou encore soumettre et traiter un sous-formulaire… Ce chapitre s'appuie sur le [[https://youtu.be/55EXq7ZjL4Q|tuto (youtube) grafikart sur les écouteurs d'événements]] Pour cela, il y a la méthode **addEventListener**\\ Tout d'abord, on sélectionne notre élément, cf. ci-dessus le § sur //querySelector//, puis on lui ajoute l'écoute : input_sig.addEventListener('input', () => { // callback qui va afficher dans la console le texte tapé dans le champ console.log(input_sig.value) }) Les [[https://developer.mozilla.org/fr/docs/Web/Events|principaux événements]] sont :  * * //click//, essentiellement pour les boutons (sous-formulaires) * //input// (sur text, textarea… survient à chaque nouveau caractère tapé, à la différence de //change//), * //change// changement de la valeur de l'input ou du basculement d'une //checkbox// (tuto à 22’30"), ou encore d'un //select// (//currentTarget.selectedOptions// -> toutes les infos) * //select multiple// 24’30’’ : Array.from(event.currentTarget.selectedOptions).map(option => option.value) * //keydown// touche appuyée, intéressant pour définir des raccourcis… document.addEventListener('keydown', e) => { if (e.ctrlKey === true && e.key ==='k') {e.preventDefault(); console.log('raccourci')}}) * //keypress//, //keyup//, suite de //keydown// * //focus//, dès qu'un élément a le focus (survol de la souris ou via tab * //blur// à la perte du focus -> traiter la valeur … cf. [[https://youtu.be/55EXq7ZjL4Q|tuto (youtube) grafikart sur les écouteurs d'événements]] à 14’20’’ ==== preventDefault ==== Cette méthode est importante pour bloquer le comportement par défaut d'un évènement (//event//), comme la redirection pour un lien, la soumission du formulaire lors du clic (//click//) du bouton… cf. tuto ci-dessous à 6’15" ==== stopPropagation ==== Autre méthode très utile, la méthode //stopPropagation// qui évite de propager l'évènement aux éléments parents… (div généralement). (tuto 8’30") ==== formData ==== cet objet permet la récupération (get) des saisies du formulaire (tuto à 16’45"), objet qui peut être modifié (set, append) avant de par exemple le transmettre au serveur.\\ Si on a besoin de modifier le formulaire en cours, on fera simplement un //querySelector// puis //element.value = // Pour récupérer le contenu du formulaire qui contient un champ //input// qui a pour //name// //location// : document.querySelector('form').addEventListener('submit', e => { e.preventDefault() const form = e.currentTarget const datas = new FormData(form) console.log(datas) console.log(datas.get('location')) }) ===== Fetch ===== tuto grafikart : https://grafikart.fr/tutoriels/javascript-promise-2068#autoplay\\ Une fois l'évènement capturé, on a souvent besoin soit de récupérer des données du serveur pour alimenter la liste d'une autocomplétion, soit de soumettre un sous-formulaire (lieu, person…).\\ On utilise dans tous ces cas la fonction //**fetch**//\\ Cette fonction exécutant une requête HTTP, la réponse n'est pas immédiate même si elle peut être très rapide. Nous allons donc généralement créer une fonction qui sera asynchrone (//async//) pour ne pas être bloquante, fonction qui appellera fetch en précisant (préfixant) l'appel avec //await// pour attendre le retour.\\ Exemple : async function testFetchWebService(server, params) { const fullUrl = server + params const r = await fetch(fullUrl, { method: 'GET', headers: { "Accept": "application/json", } }); if (r.ok === true) { return r.json(); } throw new Error('impossible de contacter le serveur'); } // et on l'appelle : const placeHolderServerUrl = 'https://jsonplaceholder.typicode.com/' const placeHolderServerParams = 'users?username=Bret' console.log('Test avec placeHolder :') testFetchWebService(placeHolderServerUrl, placeHolderServerParams).then(users => console.log(users)); ===== Sucre syntaxique ===== Ça donne un code plus concis, mais parfois incompréhensible. Je passe sur i = i + 1 qui devient i++ ou ++i L'opérateur ternaire : à peu près commun aux différents langages donc acceptable : // au lieu de : if (condition) 'valeur si vrai' else 'valeur si faux' // en une ligne : condition ? 'valeur si vrai' : 'valeur si faux' le //??// : // au lieu de if (chaine != null) chaine else '' // on a : chaine ?? ''