web-dev-qa-db-fra.com

Vue.js - Comment surveiller correctement les données imbriquées

J'essaie de comprendre comment surveiller correctement certaines variations de prop. J'ai un composant parent (fichiers .vue) qui reçoit les données d'un appel ajax, les place dans un objet et les utilise pour rendre un composant enfant via une directive v-for, en-dessous d'une simplification de mon implémentation:

<template>
    <div>
        <player v-for="(item, key, index) in players"
            :item="item"
            :index="index"
            :key="key"">
        </player>
    </div>
</template>

... puis à l'intérieur de la balise <script>:

 data(){
     return {
         players: {}
 },
 created(){
        let self = this;
        this.$http.get('../serv/config/player.php').then((response) => {
            let pls = response.body;
            for (let p in pls) {
                self.$set(self.players, p, pls[p]);
            }
    });
}

les objets sont comme ceci:

item:{
   prop: value,
   someOtherProp: {
       nestedProp: nestedValue,
       myArray: [{type: "a", num: 1},{type: "b" num: 6} ...]
    },
}

Maintenant, dans le composant "joueur" de mon enfant, j'essaie de surveiller la variation de propriété d'un élément et j'utilise:

...
watch:{
    'item.someOtherProp'(newVal){
        //to work with changes in "myArray"
    },
    'item.prop'(newVal){
        //to work with changes in prop
    }
}

Cela fonctionne mais cela me semble un peu délicat et je me demandais si c'était la bonne façon de le faire. Mon objectif est d'effectuer une action à chaque fois que prop change ou myArray obtienne de nouveaux éléments ou des variations à l'intérieur des éléments existants. N'hésitez pas à nous faire part de vos suggestions.

279
Plastic

Vous pouvez utiliser un observateur profond pour cela:

watch: {
  item: {
     handler(val){
       // do stuff
     },
     deep: true
  }
}

Cela détectera maintenant toute modification apportée aux objets du tableau item et les ajouts au tableau lui-même (si utilisé avec Vue.set ). Voici un JSFiddle: http://jsfiddle.net/je2rw3rs/

EDIT

Si vous ne souhaitez pas surveiller chaque modification apportée à l'objet de niveau supérieur et souhaitez simplement utiliser une syntaxe moins complexe pour surveiller directement les objets imbriqués, vous pouvez simplement regarder un computed à la place:

var vm = new Vue({
  el: '#app',
  computed: {
    foo() {
      return this.item.foo;
    }
  },
  watch: {
    foo() {
      console.log('Foo Changed!');
    }
  },
  data: {
    item: {
      foo: 'foo'
    }
  }
})

Voici le JSFiddle: http://jsfiddle.net/oa07r5fw/

436
craig_h

Une autre bonne approche, légèrement plus élégante, est la suivante:

 watch:{
     'item.someOtherProp': function (newVal, oldVal){
         //to work with changes in someOtherProp
     },
     'item.prop': function(newVal, oldVal){
         //to work with changes in prop
     }
 }

(J'ai appris cette approche de @peerbolte dans le commentez ici )

313
Ron C

Une autre méthode.

Ne pas utiliser fonction flèche en le faisant. Vous ne pouvez pas accéder à l'objet this.

watch:{
    'item.someOtherProp': function(newValue, oldValue){
        // Process
    }
}
7
Yasin UYSAL

Comment faire si vous voulez regarder une propriété pendant un moment et ensuite la dé-regarder?

Ou regarder une propriété de composant enfant de bibliothèque?

Vous pouvez utiliser "l'observateur dynamique":

this.$watch(
 'object.property', //what you want to watch
 (newVal, oldVal) => {
    //execute your code here
 }
)

$watch renvoie une fonction d'annulation de la correspondance qui arrête de regarder si elle est appelée.

var unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()

Aussi, vous pouvez utiliser l'option deep:

this.$watch(
'someObject', () => {
    //execute your code here
},
{ deep: true }
)

S'il vous plaît assurez-vous de jeter un oeil à la documentation

4
roli roli

Ne le voyez pas mentionné ici, mais vous pouvez également utiliser le modèle vue-property-decorator si vous étendez votre classe Vue.

import { Watch, Vue } from 'vue-property-decorator';

export default class SomeClass extends Vue {
   ...

   @Watch('item.someOtherProp')
   someOtherPropChange(newVal, oldVal) {
      // do something
   }

   ...
}
2
getglad

VueJs montre en profondeur dans les objets enfants

new Vue({
    el: "#myElement",
    data: {
        entity: {
            properties: []
        }
    },
    watch: {
        'entity.properties': {
            handler: function (after, before) {
                // Changes detected. Do work...     
            },
            deep: true
        }
    }
});
2
Alper Ebicoglu

Mon problème avec la réponse acceptée d’utiliser deep: true, c’est que lorsqu’on regarde en profondeur un tableau, je ne peux pas facilement identifier quel élément de le tableau contient le changement. La seule solution claire que j'ai trouvée est cette réponse explique comment créer un composant afin que vous puissiez observer chaque élément de tableau individuellement.

1
krubo

Une autre façon d’ajouter que j’avais l'habitude de "pirater" cette solution consistait à procéder ainsi: j'ai créé une valeur séparée computed qui renverrait simplement la valeur de l'objet imbriqué.

data : function(){
    return {
        my_object : {
            my_deep_object : {
                my_value : "hello world";
            }.
        },
    };
},
computed : {
    helper_name : function(){
        return this.my_object.my_deep_object.my_value;
    },
},
watch : {
    helper_name : function(newVal, oldVal){
        // do this...
    }
}
1
Zac