23 octobre 2022

Les événements: change, input, cut, copy, paste

Découvrons différents événements qui accompagnent les mises à jour des données.

Événement: change

L’événement change se déclenche lorsque le changement de la valeur de l’élément a fini de se réaliser.

Pour les éléments input de type text cela signifie que l’événement se produit lorsqu’ils perdent le focus.

Par exemple, pendant que nous saisissons dans le champ de texte ci-dessous – il n’y a aucun événement. Mais lorsque nous déplaçons le focus ailleurs, par exemple, en cliquant sur un bouton – il y aura un événement change:

<input type="text" onchange="alert(this.value)">
<input type="button" value="Button">

Pour les autres éléments: select, input type=checkbox/radio il se déclenche juste après les changements de sélection:

<select onchange="alert(this.value)">
  <option value="">Select something</option>
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
  <option value="3">Option 3</option>
</select>

Événement: input

L’événement input se déclenche à chaque fois qu’une valeur est modifiée par l’utilisateur.

Contrairement aux événements liés au clavier, il se déclenche sur toute modification de valeur, même celles qui n’impliquent pas d’actions du clavier: coller avec une souris ou utiliser la reconnaissance vocale pour dicter le texte.

Par exemple:

<input type="text" id="input"> oninput: <span id="result"></span>
<script>
  input.oninput = function() {
    result.innerHTML = input.value;
  };
</script>

Si nous voulons gérer chaque modification d’un <input> alors cet événement est le meilleur choix.

D’un autre coté, l’événement input ne se déclenche pas lors de la saisie au clavier et d’autres actions qui n’impliquent de changement de valeur, par ex. en appuyant sur les touches fléchées touche:⇦ touche:⇨ pendant la saisie.

smart header="Impossible d'empêcher quoi que ce soit dans `oninput`"
L'événement `input` se produit après la modification de la valeur.

Nous ne pouvons donc pas utiliser `event.preventDefault()` - c'est trop tard, il n'y aurait aucun effet.

Événements: cut, copy, paste

Ces événements se produisent lors de la coupe/copie/collage d’une valeur.

Ils appartiennent à la classe ClipboardEvent et permettent d’accéder aux données coupées/copiées/collées.

Nous pouvons également utiliser event.preventDefault() pour interrompre l’action, puis rien n’est copié/collé.

Par exemple, le code ci-dessous empêche tous ces événements cut/copy/paste et montre ce que nous essayons de couper/copier/coller:

<input type="text" id="input">
<script>
  input.onpaste = function(event) {
    alert("paste: " + event.clipboardData.getData('text/plain'));
    event.preventDefault();
  };

  input.oncut = input.oncopy = function(event) {
    alert(event.type + '-' + document.getSelection());
    event.preventDefault();
  };
</script>

Remarque : à l’intérieur des gestionnaires d’événements cut et copy, un appel à event.clipboardData.getData(...) renvoie une chaîne vide. C’est parce que techniquement, les données ne sont pas encore dans le presse-papiers. Si nous utilisons event.preventDefault(), il ne sera pas du tout copié.

Ainsi, l’exemple ci-dessus utilise document.getSelection() pour obtenir le texte sélectionné. Vous pouvez trouver plus de détails sur la sélection de documents dans l’article Selection et Range.

Il est possible de copier/coller pas seulement du texte, mais tout. Par exemple, nous pouvons copier un fichier dans le gestionnaire de fichiers du système d’exploitation et le coller.

C’est parce que clipboardData implémente l’interface DataTransfer, couramment utilisée pour le glisser-déposer et le copier/coller. C’est un peu hors de notre portée maintenant, mais vous pouvez trouver ses méthodes dans la spécification DataTransfer.

En outre, il existe une API asynchrone supplémentaire pour accéder au presse-papiers : navigator.clipboard. Plus d’informations à ce sujet dans la spécification Clipboard API and events, non pris en charge par Firefox.

Restrictions de sécurité

Le presse-papiers est une chose “globale” au niveau du système d’exploitation. Un utilisateur peut basculer entre différentes applications, copier/coller différentes choses, et une page de navigateur ne devrait pas voir tout cela.

Ainsi, la plupart des navigateurs permettent un accès en lecture/écriture transparent au presse-papiers uniquement dans le cadre de certaines actions de l’utilisateur, telles que le copier/coller, etc.

Il est interdit de générer des événements de presse-papiers “personnalisés” avec dispatchEvent dans tous les navigateurs sauf Firefox. Et même si nous parvenons à envoyer un tel événement, la spécification indique clairement que de tels événements “synthétiques” ne doivent pas donner accès au presse-papiers.

Même si quelqu’un décide d’enregistrer event.clipboardData dans un gestionnaire d’événements, puis d’y accéder plus tard, cela ne fonctionnera pas.

Pour réitérer, event.clipboardData fonctionne uniquement dans le contexte des gestionnaires d’événements initiés par l’utilisateur.

D’autre part, navigator.clipboard est l’API la plus récente, destinée à être utilisée dans n’importe quel contexte. Elle demande l’autorisation de l’utilisateur, si nécessaire.

Récapitulatif

Événements de changement de données:

Événement Description Specials
change Une valeur a été modifiée Pour les entrées de texte, les déclencheurs sont sur la perte de mise au point.
input Pour les champs textes à chaque modification. Se déclenche immédiatement contrairement à change.
cut/copy/paste Les actions couper/copier/coller. L’action peut être empêchée. La propiété event.clipboardData donne un accès en lecture/écriture au presse-papiers. Tous les navigateurs, à l’exception de Firefox, prennent également en charge navigator.clipboard.

Exercices

importance: 5

Create an interface that allows to enter a sum of bank deposit and percentage, then calculates how much it will be after given periods of time.

Here’s the demo:

Any input change should be processed immediately.

The formula is:

// initial: the initial money sum
// interest: e.g. 0.05 means 5% per year
// years: how many years to wait
let result = Math.round(initial * (1 + interest) ** years);

Open a sandbox for the task.

Carte du tutoriel