0

I know you can use v-model to bind a value to an input in the same component. How do you create a wrapper component for an input and bind a value to it?

Login.vue

<template>
  <div id="Login">
    <Input v-bind:value="email"/>    
    <Input v-bind:value="password"/>

  </div>
</template>
<script>
  import Input from './Input.vue'
  import Button from './Button'

  export default {
    name: 'Login',
    components: {
        Input,
        Button,
    },
    data: () => ({
        email:'test',
        password:'test',
    }),
    methods: {
        login: () => { debugger; }, //this.email and this.password are still set to test
    }
  }
</script>

Input.vue

<template>
  <div class="input>
   <input v-model="value"/>
  </div>
</template>
<script>
  export default {
    name: 'Input',
    props: {
        value: String,
    },
  }
</script>

Current set up results in

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

Is the only way to do this by emitting an event?

3 Answers 3

2

The best way is use v-model for wrapper and on/emit for input

<div id="Login">
    <Input v-model="email"/>    
    <Input v-model="password"/>    
</div>

...

<div class="input>       
   <input        
     v-bind:value="value"
     v-on:input="$emit('input', $event.target.value)"
   >
</div>
Sign up to request clarification or add additional context in comments.

Comments

2

If I got it correctly, you can try to create transparent wrapper (in my case AppInput)

SomeParent.vue

<div>
  <AppInput v-model="parentModel" />
</div>

AppInput.vue

<template>
  <input
    class="app-input"
    v-bind="$attrs"
    :value="value"
    v-on="{
      ...$listeners,
      input: event => $emit('input', event.target.value)
    }">
</template>
<script>
export default {
  name: "AppInput",
  inheritAttrs: false,
  props: ["value"]
};
</script>

one of articles

Comments

1

You can implement v-model directly in the input component by doing so.

<template>
  <div class="input">
   <input :value="value" @input="$emit('input', $event.target.value)"/>
  </div>
</template>
<script>
  export default {
    name: "Input",
    props: ["value"]
  }
</script>

And then use it in your parent component like this:

<template>
  <div id="Login">
    <Input v-model="email"/>    
    <Input v-model="password"/>
  </div>
</template>
<script>
  import Input from "./Input.vue"
  import Button from "./Button"

  export default {
    name: "Login",
    components: {
        Input,
        Button,
    },
    data: () => ({
        email: "test",
        password: "test",
    }),
    methods: {
        login: () => { debugger; }, //this.email and this.password are still set to test
    }
  }
</script>

See here

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.