0

I've created a vue component to reuse thoughout my app but I'm struggling with one aspect the value being initially displayed in the input text field. It feels like there is something I'm misunderstanding about the the render cycle and how value binding works.

Here is the Vue component that I've made:

<template>
  <div class="my-2">
    <label for="name">{{ label }} </label>
    <input
      :id="id"
      :name="name"
      :class="{
        input: true,
        'input-error': errorMessage && errorMessage != '',
      }"
      :value="value"
      v-on:input="action"
      :type="type"
      :required="!!required"
      v-once
    />
    <p v-show="errorMessage && errorMessage != ''" class="error-message">
      {{ errorMessage }}
    </p>
  </div>
</template>

<script>
export default {
  name: "BaseInput",
  props: [
    "defaultValue",
    "label",
    "type",
    "id",
    "name",
    "errorMessage",
    "required",
  ],
  computed: { 
    value() {
      console.log(this.defaultValue);
      return this.defaultValue
    },
  },
  methods: {
    action(e) {
      this.$emit("input", e.target.value);
    },
  },
};
</script>

and I reference it in my parent component as such:

<base-input label="Base Input 2" id="in2" name="name" v-model="value"></base-input> {{value}}

when the page loads the {{value}} displays value as expected, but the input does not actually display the text

1
  • You need to listen for @input in the parent Commented Oct 27, 2020 at 13:55

2 Answers 2

2

Change the defaultValue prop to value as shown below. This should setup a two-way binding between your child and parent.

<template>
      <div class="my-2">
        <label for="name">{{ label }} </label>
        <input
          :id="id"
          :name="name"
          :class="{
            input: true,
            'input-error': errorMessage && errorMessage != '',
          }"
          :value="value"
          v-on:input="action"
          :type="type"
          :required="!!required"
          v-once
        />
        <p v-show="errorMessage && errorMessage != ''" class="error-message">
          {{ errorMessage }}
        </p>
      </div>
    </template>
    
    <script>
    export default {
      name: "BaseInput",
      props: [
        "value",
        "label",
        "type",
        "id",
        "name",
        "errorMessage",
        "required",
      ],
      methods: {
        action(e) {
          this.$emit("input", e.target.value);
        },
      },
    };
    </script>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I appreciate you putting the time in to help me on this
1

in order to achieve a two way binding on a custom component you have to follow a special syntax on your child component. You have to pass the value as a prop and emit the input on a method. Try updating you're code like this:

<template>
  <div class="my-2">
    <label for="name">{{ label }} </label>
    <input
      :id="id"
      :name="name"
      :class="{
        input: true,
        'input-error': errorMessage && errorMessage != '',
      }"
      :value="value"
      v-on:input="action"
      :type="type"
      :required="!!required"
      v-once
    />
    <p v-show="errorMessage && errorMessage != ''" class="error-message">
      {{ errorMessage }}
    </p>
  </div>
</template>

<script>
export default {
  name: "BaseInput",
  props: [
    "defaultValue",
    "label",
    "type",
    "id",
    "name",
    "errorMessage",
    "required",
    "value"
  ],
  methods: {
    action(e) {
      this.$emit("input", e.target.value);
    },
  },
};
</script>

with value as a prop and not a computed property. More about this on the docs

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.