2 votes

La directive v-if ne fonctionne pas lors du changement d'onglet

J'essaie de construire un système de liste simple qui affiche une liste d'articles pour différentes plates-formes, chaque plate-forme est sur un onglet séparé. J'ai créé la logique de changement d'onglet via VueJS à partir de rien.

Ce que je fais :

En fait, j'ai deux plateformes : twitter et facebook. Lorsque l'utilisateur clique sur l'un des onglets, le frontend envoie une requête ajax à mon serveur pour récupérer les messages de cette plateforme et les rendre via v-for.

J'ai ajouté un bouton appelé edit pour chaque message, lorsque l'utilisateur appuie dessus, il appelle une fonction edit(p), où p est le message courant que l'utilisateur veut éditer.

dans edit(p) je change un attribut p.editing qui en utilisant v-if montre une zone de texte et un timepicker (j'utilise flatpicker) pour ce post .

Ce qui ne va pas :

Tout cela fonctionne bien lorsque je suis sur le premier onglet, mais une fois que je change d'onglet, cela cesse de fonctionner, après débogage j'ai remarqué que v-if ne fonctionne pas l'événement p.editing est mis à jour lorsque edit(p) est appelé, voici le code :

var posts_app = new Vue({
    el: "#posts_app",
    data: {
        platforms : ['facebook','twitter'],
        current_tab: {
            'facebook' : true,
            'twitter': false
        },
        platform_posts: {
            'facebook': [],
            'twitter': []
        },
        posts: undefined,
    },
    methods:{
        showTab: function(i){
            platform = this.platforms[i]
            // UI stuff : to make the clicked tab active
            for(p in this.current_tab){
                if(p == platform){
                    this.current_tab[p] = true
                }
                else{
                    this.current_tab[p] = false
                }
            }
            // Show content by platform
            this.posts = this.platform_posts[platform]
        },
        edit: function(p){
            p.editing = true
            console.log(p)
            Vue.nextTick(function(){
                document.getElementsByClassName("dt-input")[0].flatpickr({enableTime : true});
            })
        },
        save: function(p){
            p.editing = false
        }
    },
    created(){
        self = this
        posts_loaded = false

        for(var i = 0;i < this.platforms.length; i++){
            (function(index){           
                self.$http.get('/fan/posts',{params:{platform : self.platforms[index]}}).then(function(resp){
                self.platform_posts[self.platforms[index]] = resp.body
                posts_loaded = true

            })//Promise of Ajax call
            }// Closure body
            )(i)//Closure
        }

        this.showTab(0)
    },
    delimiters: ['[[',']]']

})

et mon modèle html de base :

 <div class = "panel-body">
        <img class = "pull-right responsive" v-bind:src = "p.image"/>
        <textarea v-if = "p.editing" class = "post-text-input" v-model = "p.text"></textarea>
        <p class = "post-text" v-if = "!p.editing">[[p.text]]</p>
        <p class = "post-source" v-if = "p.type == 'article'"> Source : [[post_source(p)]]</p>
        <p class = "post-time"><b>Scheduled on <i v-if = "!p.editing">[[p.time]] </i></b>
            <input placeholder="Choose a date and a time" class = "flatpickr dt-input" v-model = "p.time" v-if = "p.editing" />
        </p>

       </div>
       <div class = "panel-footer clearfix">
         <button class = "btn btn-danger">Delete</button>
         <button class = "btn btn-info pull-right" @click = "edit(p)" v-if = "!p.editing">Edit</button>
         <button class = "btn btn-success pull-right" @click = "save(p)" v-if = "p.editing">Save</button>

       </div>

Explication du code :

Ainsi, lorsqu'un onglet est cliqué, showTab(index) est appelé où index est le numéro de l'onglet, si index est 0 alors nous sommes passés à l'onglet facebook, si c'est 1 alors nous sommes dans l'onglet twitter, nous envoyons une requête AJAX pour obtenir les messages pour cette plateforme actuelle (onglet) et le remplir dans platform_posts[current_platform], nous les rendons ensuite via v-for . Tout cela fonctionne comme un charme.

Deuxièmement, lorsque l'utilisateur clique sur le bouton d'édition pour un article donné, il remplace l'élément de paragraphe texte par un textarea utilisant v-model pour garder la trace des changements et mettre à jour le paragraphe temps avec une entrée qui agit comme un sélecteur de date via la bibliothèque flatpickr. En fait, cette librairie peut transformer n'importe quelle entrée en un sélecteur de date en utilisant cette ligne de code :

elemnt.flatpickr({config_options})

Où élément est un élément HTML . Vous pouvez remarquer que j'utilise Vue.nextTick, c'est pour m'assurer que l'entrée n'est plus cachée (elle ne devrait plus l'être puisque p.editing est mis à jour) . Tout cela fonctionne comme un charme lorsque je suis sur le premier onglet, le problème est que lorsque je change d'onglet, cela ne fonctionne plus .

Voici un gif que j'ai fait pour vous montrer l'erreur : http://imgur.com/a/QME4P

Comme vous pouvez le constater, le comportement est très bizarre, il fonctionne parfaitement sur l'onglet twitter et il est bizarre sur l'onglet facebook .

1voto

For the Name Points 961

On dirait que vous brisez la réactivité quelque part. Lisez sur la réactivité . En bref, vous ne pouvez pas modifier un tableau ou ajouter une nouvelle propriété à un objet déjà créé.

Par exemple, au lieu de p.editing = true vous pouvez faire :

this.$set(p, 'editing', true)

Un autre concept clé consiste à remplacer un tableau au lieu de le modifier.

Je vous recommande de déplacer votre get posts hors de created() et dans une méthode appelée par created(), car vous pourriez vouloir le réutiliser pour tirer des posts à nouveau. Vous devriez également définir posts à un tableau vide au lieu de undefined.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X