2017-10-17 15 views
3

J'ai des problèmes pour implémenter un composant modal dynamique dans Vue.Composants modaux multiples avec Vue

Une approche courante Je suis pour afficher un ensemble de données extraites de la base de données est que je vider chacune des lignes dans un élément de tableau HTML en itérant sur chacune des lignes du résultat db. Quelque chose comme ceci:

Comme vous pouvez le voir dans la capture d'écran, chacune des lignes a un ou plusieurs boutons qui sont générés dynamiquement par la boucle. Pour lier un composant modal à chacun des boutons (disons les boutons Supprimer dans ce scénario), je fais quelque chose comme ça.
HTML:

<div id="app"> 
    <?php foreach($result as $x): ?> 
     <modal v-if="showModal">I am Modal $x</modal> 
     <btn @trigger="onShowModal">Button $x</btn> 
    <?php endforeach; ?> 
</div> 

Donc, si j'ai trois lignes dans mon résultat, le bloc précité du code prendra la forme de quelque chose comme ceci:

<div id="app"> 
     <modal v-if="showModal">I am Modal 1</modal> 
     <btn @trigger="onShowModal">Button 1</btn> 

     <modal v-if="showModal">I am Modal 2</modal> 
     <btn @trigger="onShowModal">Button 2</btn> 

     <modal v-if="showModal">I am Modal 3</modal> 
     <btn @trigger="onShowModal">Button 3</btn> 
</div> 

Et voici ce que je fais à la fin JavaScript:

JavaScript:

Le problème avec cette approche est que lorsque je clique sur l'un des boutons Supprimer, j'obtiens une pile de modaux au lieu du modal que je voulais voir. Et c'est parce que je mets showModal à true et si vous voyez le bloc HTML rempli, vous verrez que chacun des modaux est défini sur v-if="showModal".

Click here to see a demo

Et comme je commence à comprendre la relation-frontend backend, j'apprends que ce modèle apparaît plus souvent dans une application. Comment résoudre ce problème (avec un niveau très favorable aux débutants)?

Répondre

2

Le problème principal est que vous référencez la même propriété de données showModal sur tous les composants modaux.

Vous pouvez créer un autre composant pour encapsuler le bouton et la paire de composants modaux. De cette façon, il y a une propriété de données showModal pour chaque modal et btn paire:

Vue.component('btn',{ 
 
    template: `<button @click="$emit('trigger')"><slot></slot></button>`, 
 
}); 
 

 
Vue.component('modal',{ 
 
    template: `<p><slot></slot></p>`, 
 
}); 
 

 
Vue.component('modal-btn', { 
 
    template: ` 
 
    <div> 
 
     <modal v-if="showModal"> 
 
     <slot>I am a modal</slot> 
 
     </modal> 
 
     <btn @trigger="showModal = true">Show Modal</btn> 
 
    </div> 
 
    `, 
 
    data() { 
 
    return { showModal: false } 
 
    } 
 
}); 
 

 
new Vue({ 
 
    el: '#app', 
 
    data: { 
 
    showModal: false 
 
    }, 
 
    methods: { 
 
    onShowModal(){ 
 
     this.showModal = true; 
 
    } 
 
    } 
 
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script> 
 
<div id="app"> 
 
    <modal-btn></modal-btn> 
 
    <modal-btn>I am another modal</modal-btn> 
 
    <modal-btn>I'm a third modal</modal-btn> 
 
</div>

+0

Dans le cas d'un 'composante modale button', si je voulait que le nom de la propriété de données et la fonction à exécuter dans '@ trigger' soient fournis par l'utilisateur plutôt que par la fonction et les fonctions statiques' showModal' et 'onShowModal'. Je veux dire quelque chose comme ceci: ''? – Eisenheim

+1

Dans ce cas, votre gestionnaire '@ trigger' dans le composant' modal-btn' devrait émettre un événement (disons '$ emit ('show')'), alors le composant parent devrait gérer cet événement via ' thanksd

+0

Merci, ça s'occupe de l'émission de l'événement Mais qu'en est-il de la directive 'v-if' dans' '? Comment puis-je lier la valeur de v-if à une propriété data au choix de l'utilisateur? dire, 'showConfirmModal'? Je suis coincé avec' ' – Eisenheim

1

Le problème que vous rencontrez est que tous les modaux sont liés à un attribut de données (showModal) de sorte que tous les modaux montrera quand vous définissez ceci à vrai.La solution est d'isoler chaque bouton dans son propre composant qui a son propre plutôt attribut showModal que de l'émettre au parent:

Vue.component('btn',{ 
    template: `<div><button @click="showModal = true"><slot></slot></button> 
    <modal v-if="showModal">I am a modal for {{button}}</modal></div>`, 
    props: ['button'], 
    data(){ 
    return { 
     showModal: false 
    } 
    } 
}); 

 

Et voici le updated JSBin

Si vous avez besoin de différents modaux pour chaque type de bouton, créez simplement deux composants de bouton edit-button, delete-button etc.

1

Vous pourriez avoir besoin d'une application plus centrée sur les données Gardez ce que vous essayez. Quelque chose comme,

<!DOCTYPE html> 
<html> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script> 
</head> 
<body> 
    <div id="app"> 
    <template v-for="item in items"> 
     <modal v-if="item.show">I am a dummy Modal for {{item.name}}</modal> 
     <btn @trigger="item.show = !item.show">Button for {{item.id}}</btn> 
    </template> 
    </div> 

    <script> 
    Vue.component('btn',{ 
     template: `<button @click="$emit('trigger')"><slot></slot></button>`, 
    }); 

    Vue.component('modal',{ 
     template: `<p><slot></slot></p>`, 
    }); 

    new Vue({ 
     el: '#app', 
     data: { 
     items: [ 
      {id: 1, name: 'item 1', show: false}, 
      {id: 2, name: 'item 2', show: false}, 
      {id: 3, name: 'item 3', show: false} 
     ], 
     showModal: false 
     }, 
     methods: { 
     onShowModal(){ 
      this.showModal = true; 
     } 
     } 
    }); 
    </script> 
</body> 
</html> 

Vous pouvez alors obtenir aussi loin avec un seul élément modal qui reçoit les données applicables, il doit afficher au moyen d'un prop