web-dev-qa-db-fra.com

[Vue warn]: la propriété ou la méthode n'est pas définie sur l'instance mais référencée lors du rendu

var MainTable = Vue.extend({
  template: "<ul>" +
    "<li v-for='(set,index) in settings'>" +
    "{{index}}) " +
    "{{set.title}}" +
    "<button @click='changeSetting(index)'> Info </button>" +
    "</li>" +
    "</ul>",
  data: function() {
    return data;
  }
});

Vue.component("main-table", MainTable);

data.settingsSelected = {};
var app = new Vue({
  el: "#settings",
  data: data,
  methods: {
    changeSetting: function(index) {
      data.settingsSelected = data.settings[index];
    }
  }
});

Avec le code ci-dessus, l'erreur ci-dessous se produit lorsque l'utilisateur clique sur le bouton.

[Vue warn]: La propriété ou la méthode "changeSetting" n'est pas définie sur l'instance mais référencée lors du rendu. Assurez-vous de déclarer les propriétés de données réactives dans l'option de données. (trouvé dans <MainTable>)

59
Lorenzo D'Isidoro

Problème

[Vue warn]: Property or method "changeSetting" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in <MainTable>)

L'erreur se produit car la méthode changeSetting est référencée dans le composant MainTable ici:

    "<button @click='changeSetting(index)'> Info </button>" +

Cependant, la méthode changeSetting n'est pas définie dans le composant MainTable. Il est défini dans le composant racine ici:

var app = new Vue({
  el: "#settings",
  data: data,
  methods: {
    changeSetting: function(index) {
      data.settingsSelected = data.settings[index];
    }
  }
});

Il ne faut pas oublier que les propriétés et les méthodes ne peuvent être référencées que dans la portée où elles sont définies.

Tout dans le modèle parent est compilé dans la portée parent; tout dans le modèle enfant est compilé dans la portée enfant.

Vous pouvez en savoir plus sur la portée de la compilation des composants dans documentation de Vue.

Que puis-je faire à ce sujet?

Jusqu'à présent, il a beaucoup été question de définir les éléments dans le champ d'application correct. Le correctif consiste donc simplement à déplacer la définition de changeSetting dans le composant MainTable?

Cela semble aussi simple que cela, mais voici ce que je recommande.

Vous voudriez probablement que votre composant MainTable soit un composant muet/de présentation. ( Here est quelque chose à lire si vous ne savez pas ce que c'est mais un tl; dr est que le composant est juste responsable de rendre quelque chose - pas de logique). L'élément smart/container est responsable de la logique - dans l'exemple donné dans votre question, le composant racine serait le composant smart/container. Avec cette architecture, vous pouvez utiliser les méthodes de communication parent-enfant de Vue pour que les composants puissent interagir. Vous transmettez les données pour MainTable via props et émettez des actions utilisateur de MainTable vers son parent via événements . Cela pourrait ressembler à quelque chose comme ça:

Vue.component('main-table', {
  template: "<ul>" +
    "<li v-for='(set, index) in settings'>" +
    "{{index}}) " +
    "{{set.title}}" +
    "<button @click='changeSetting(index)'> Info </button>" +
    "</li>" +
    "</ul>",
  props: ['settings'],
  methods: {
    changeSetting(value) {
      this.$emit('change', value);
    },
  },
});


var app = new Vue({
  el: '#settings',
  template: '<main-table :settings="data.settings" @change="changeSetting"></main-table>',
  data: data,
  methods: {
    changeSetting(value) {
      // Handle changeSetting
    },
  },
}),

Ce qui précède devrait suffire à vous donner une bonne idée de ce qu’il faut faire et à savoir comment résoudre votre problème.

74
Wing