2
votes

I'm using Vue.js. From my template I include the child component (componentB) which includes several input elements. I want to initialize those input elements from my parent template. I found a way to do this (see code below). However, I'm wondering if this is a correct way, as the articles I have read so far use different approaches (e.g. with $emit):

Can you confirm that my code below matches the Vue.js design concepts or are there flaws?

<template>
  <div>
    <div class="md-layout">
      <div class="md-layout-item md-size-100">
        <ComponentB ref="componentB" v-model="componentB"></ComponentB>
      </div>
    </div>
  </div>
</template>
<script>
import { ComponentB } from "@/components";
export default {
  components: {
    ComponentB
  },
  data() {
    return {
      componentB: {
        textInputField: "my-initial-value"
      }
    };
  },
  methods: {
    validate() {
      return this.$refs.componentB.validate().then(res => {
        this.$emit("on-validated", res);
        return res;
      });
    }
  }
};
</script>
<style></style>

Form componentB

<template>
<div>
    <md-field
            :class="[
            { 'md-valid': !errors.has('textInputField') && touched.textInputField },
            { 'md-form-group': true },
            { 'md-error': errors.has('textInputField') }
          ]"
    >
        <md-icon>label_important</md-icon>
        <label>My text input</label>
            <md-input
                    v-model="textInputField"
                    data-vv-name="textInputField"
                    type="text"
                    name="textInputField"
                    required
                    v-validate="modelValidations.textInputField"
            >
            </md-input>
        <slide-y-down-transition>
            <md-icon class="error" v-show="errors.has('textInputField')"
            >close</md-icon
            >
        </slide-y-down-transition>
        <slide-y-down-transition>
            <md-icon
                    class="success"
                    v-show="!errors.has('textInputField') && touched.textInputField"
            >done</md-icon
            >
        </slide-y-down-transition>
    </md-field>
</div>
</template>
<script>
import { SlideYDownTransition } from "vue2-transitions";
export default {
  name: "componentB",
  props: ['value'],
  components: {
    SlideYDownTransition
  },
  computed: {
    textInputField: {
      get() {return this.value.textInputField},
      set(textInputField) { this.$emit('input', { ...this.value, ['textInputField']: textInputField })}
    }
  },
  data() {
    return {
      touched: {
        textInputField: false
      },
      modelValidations: {
        textInputField: {
          required: true,
          min: 5
        }
      }
    };
  },
  methods: {
    getError(fieldName) {
      return this.errors.first(fieldName);
    },
    validate() {
      return this.$validator.validateAll().then(res => {
        return res;
      });
    }
  },
  watch: {
    textInputField() {
      this.touched.runnerName = true;
    }
  }
};
</script>
<style></style>
1
data/propeties transfer (and in your case intialization) from parent to child ideally should happen via props. And $emit is a general use case for other way round OR pubsub.ambianBeing
understood. additionally, can you see any issues with the current code?justjulian

1 Answers

-1
votes

The simplest way to pass data to child component is to use props, which are then available in the child component and can pass the values back up to the parent.

https://vuejs.org/v2/guide/components-props.html

// PARENT COMPONENT

<ComponentB :textInputField="textInputField" ...></ComponentB>

// CHILD COMPONENT
// TEMPLATE SECTION
<md-input
    v-model="textInputField"
    value="textInputField"
    ...
    >
// SCRIPT SECTION
export default {
    props: {
        textInputField: String
    }
}