Click event sur un élément dans un block affiché dans un v-if


#1

Bonjour tout le monde,

J’ai une modal que j’affiche ou non par un v-if et dans laquelle j’ai un bouton. Par défaut cette modal n’est pas affichée (et donc pas dans le DOM puisque v-if), aussi lorsque je veux attacher un click event sur mon bouton via son ID c’est impossible puisqu’il ne le trouve pas. J’ai bien contourné le problème avec un v-show, mais y a t’il une solution en gardant le v-if ?

D’avance merci,
Jules

PS: bon j’aurais pu l’écrire dans le forum anglais mais je me suis dit qu’il serait bon d’alimenter un peu le forum Français non !? :slight_smile:


#2

Oui, je t’en remercie :slight_smile:


Pour répondre à ta question, modifier le DOM réel d’un template Vue par l’utilisation de document.getElementBy... ou de document.createElement (ou via l’utilisation de jQuery) est quelque chose de très hasardeux puisque Vue ne travail pas sur le DOM réel mais sur le DOM virtuel. Aussi tout changement produit par Vue sur le DOM virtuel est répercuté sur le DOM réel mais tout ce que tu auras pu faire comme action sur le DOM réel n’est pas répercuté dans le DOM virtuel de Vue.

Pour placer des évènements sur un template Vue, il faut utiliser la directive v-on sur l’élément en question. Si tu veux que ce soit l’évènement click, il faut le préciser ainsi v-on:click soit par exemple :

vue

<div class="test">
  <button v-on:click="show">Montrer</button>
  <div v-if="isDisplay">
    <p>Je suis visible !</p>
    <button v-on:click="hide">Cacher</button>
  </div>
</div>

modèle

new Vue({
  el: '.test',
  data: {
    isDisplay: false
  },
  methods: {
    show: function () {
      this.isDisplay = true;
    },
    hide: function () {
      this.isDisplay = false;
    }
  }
});

Tu remarqueras que dans cette configuration la source générée sera :

<div class="test"><button>Montrer</button> <!----></div>

En cliquant sur « Montrer » le DOM est modifié tel que souhaité :

<div class="test"><button>Montrer</button> <div><p>Je suis visible !</p> <button>Cacher</button></div></div>

Si tu souhaites « récupérer » en dehors de Vue ton élément bouton interne il n’y a pas de miracle : tu ne pourras le faire que quand celui-ci existera, c.-à-d., après que la condition v-if="isDisplay" soit évaluée à true.

On peut donc repasser en Vanilla.js dans une fonction Vue pour récupérer l’élément tel que cela aurait été fait actuellement comme ceci :slight_smile:

vue

<div class="test">
  <button v-on:click="show">Montrer</button>
  <div v-if="isDisplay">
    <p>Je suis visible !</p>
    <button class="hide">Cacher</button>
  </div>
</div>

modèle

new Vue({
  el: '.test',
  data: {
    isDisplay: false
  },
  methods: {
    show: function () {
      var self = this;
     
      self.isDisplay = true;
    
      Vue.nextTick(function () {
        var button = document.getElementsByClassName("hide")[0];
   
        button.addEventListener("click", function () {
          self.isDisplay = false;
        });
      });
    }
  }
});

Ici on s’occupe d’adresser l’élément « non présent dans le DOM » aussitôt que celui-ci est disponible (quand isDisplay passe à true) dans Vue.nextTick(...) (car le changement dans le DOM n’est pas synchrone, et il faut attendre le prochain tour de boucle de Vue pour que le bouton soit accessible dans la source).
Quand on détruit l’élément en cliquant sur le bouton, il est détruit pour le DOM réel (dans le DOM Virtuel de Vue, il y a toujours les infos qu’il faut pour le recréer). Comme il est détruit du DOM réel, l’évènement click est détruit. Il sera réaffecté à un nouveau bouton lors du prochain appel de show et ainsi de suite.

Mais, comme tu peux le constater dans mon premier exemple, pourquoi faire ça en Vanilla.js quand Vue se débrouille comme un chef !


#3

Woua top merci beaucoup pour ta réponse, tout est très clair … j’ai bien fait de poster sur le forum Français, je recommencerai :wink: