127 votes

v-modèle et les composants enfants ?

J'ai un formulaire et je lie une entrée en utilisant v-model :

<input type="text" name="name" v-model="form.name">

Maintenant, je veux extraire l'entrée et en faire un composant propre, comment lier les valeurs du composant enfant à l'objet parent ? form.name ?

3 votes

3voto

Pawel Kwiecien Points 41

L'exemple ci-dessous vous montre comment définir le modèle du composant parent au composant enfant et synchroniser les données entre eux. Ceci est très utile lorsque vous divisez les formulaires d'application en différents composants et que vous les utilisez dans des contextes différents. De cette façon, vous pouvez utiliser, par exemple, des fragments de formulaire (composants) à différents endroits sans vous répéter.

COMPOSANT PARENT

<template lang="pug">

  .parent
    Child(:model="model")
    br

    label(for="c") Set "c" from parent  
    input(id="c", v-model="model.c")

    .result.
      <br>
      <span> View from parent :</span>
      <br>
      a = {{ model.a }} 
      <br>
      b = {{ model.b }}
      <br>
      c = {{ model.c }}

</template>

<script>

import Child from './components/child.vue'

export default {

name: "App",

components: {
  Child
  },

  data() {
    return {
      // This model is set as a property for the child
      model: {
        a: 0,
        b: 0,
        c: 0
      }
    }
  },

};
</script>

COMPOSANT ENFANT

<template lang="pug">

  .child
    label(for="a") Set "a" from child  
    input(id="a", v-model="internalModel.a", @input="emitModel")
    br
    br

    label(for="b") Set "b" from child  
    input(id="b", v-model="internalModel.b", @input="emitModel")

    .result
      br
      span View from child
      br
      | a = {{ internalModel.a }} 
      br
      | b = {{ internalModel.b }}
      br
      | c = {{ internalModel.c }}

</template>

<script>

export default {

  name: 'Child',
  props: {
    model: {
      type: Object
    }
  },

  data() {
    return {
      internalModel: {
        a:0,
        b:0,
        c:0
      }
    }
  },

  methods: {
    emitModel() {
      this.$emit('input', this.internalModel)
    }
  },
  mounted() {
    this.internalModel = this.model;
  }

}
</script>

0 votes

Je ne sais pas s'il y a un côté négatif à cette solution, mais pour moi, c'était très logique ! merci de partager !

2voto

Susei Points 941

Lier des données à une case à cocher personnalisée ou à un ensemble de cases à cocher est très différent de les lier à une entrée de texte :

https://www.smashingmagazine.com/2017/08/creating-custom-inputs-vue-js/

<template>
  <label>
    <input type="checkbox" :checked="shouldBeChecked" :value="value" @change="updateInput">
    {{ label }}
  </label>
</template>
<script>
export default {
  model: {
    prop: 'modelValue',
    event: 'change',
  },
  props: {
    value: {
      type: String,
    },
    modelValue: {
      default: false,
    },
    label: {
      type: String,
      required: true,
    },
    // We set `true-value` and `false-value` to the default true and false so
    // we can always use them instead of checking whether or not they are set.
    // Also can use camelCase here, but hyphen-separating the attribute name
    // when using the component will still work
    trueValue: {
      default: true,
    },
    falseValue: {
      default: false,
    }
  },
  computed: {
    shouldBeChecked() {
      if (this.modelValue instanceof <span class="hljs-built_in">Array) {
        return this.modelValue.includes(this.value);
      }
      // Note that `true-value` and `false-value` are camelCase in the JS
      return this.modelValue === this.trueValue;
    }
  },
  methods: {
    updateInput(event) {
      let isChecked = event.target.checked;

      if (this.modelValue instanceof Array) {
        let newValue = [...this.modelValue];

        if (isChecked) {
          newValue.push(this.value);
        } else {
          newValue.splice(newValue.indexOf(this.value), 1);
        }

        this.$emit('change', newValue);
      } else {
        this.$emit('change', isChecked ? this.trueValue : this.falseValue);
      }
    }
  }
}
</script>

2voto

Soth Points 349

En utilisant ce qui suit, vous pouvez transmettre tous les attributs d'entrée comme le placeholder :

Vue.component('my-input', {
  template: `<div>
    <input v-bind="$attrs" :value="value" @input="$emit('input', $event.target.value)">
    </div>`,
  inheritAttrs: false,
  props: ["value"],
})
new Vue({
  el: '#app',
  data: () => ({
    name: "",
  }),
})

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
  <div>Name: {{name}}</div>
  <input placeholder="Standard Input" v-model="name">
  <my-input placeholder="My Input" v-model="name"></my-input>
</div>

1voto

En plus de la méthode ci-dessus, il existe une mise en œuvre plus simple

composant parent

const value = ref('');

// provide value
provive('value', value);

composant enfant

// inject value
const value = inject('value');

<input v-modelValue="value" />

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