3

I am on migrating to Vue from React, and I just liked the v-model thing Vue offers. Now I am in a situation and not able to find out what is the vue-ish way of doing this.

Here is how my component tree looks like:

- FormContainer
  -FormView
    - CustomInput
      - input

I have my states in FormContainer let's call it name and age. I want to avoid writing custom setter methods as I usually do using v-model, how can I go about passing the data down to the input component.

Currently I am doing something like this:

// in my container
<form-view :name="name" :age="age" />

// in my form view I am doing something like
<custom-input v-model="age"/>
<input v-model="name" />

both of them do not work and I get the following error Avoid mutating a prop directly

I should be able to do something like

<form-view @age="age" :age="age" @name="name" :name="name"/>

or something similar. Please let me know if you need more details on this.

2
  • I'm quite new to Vue myself, but the @ symbol is supposed to be a shortcut for v-on: - are you sure you are using it correctly here? To pass variables down to the lower components, you use bind to assign to the props variables in the Vue component. See vuejs.org/v2/guide/index.html#Composing-with-Components Commented Aug 18, 2017 at 22:36
  • Ya that is just a thought, I'm not using it that way. I will update my question with what I am doing. Commented Aug 18, 2017 at 22:38

1 Answer 1

1

I've answered this question twice already, and though my answers had merit, I don't think they were quite on-target for your question, so I've deleted them.

Fundamentally, you want events to "bubble up" from the elements where the events are happening to the Vue that owns the data items. Vue events don't bubble, but native events do, so if you have a native input event being generated at the bottom of a hierarchy, you can catch it with @input.native in any component up the tree from there.

For the example you gave, if the name and age data items live in the top-level Vue, the outermost component can take them as props with the .sync modifier. That means that any update:name and update:age events from the component will result in the data items being updated. So far so good.

Moving inside the form-view component, we have a native input element. Normally, it emits native input events. We want those to bubble up as update:name events, so we handle that like so:

 <input :value="name" @input="$emit('update:name', $event.target.value)">

Now here's the fun part: inside the form-view component, we have the custom-input component. Somewhere in its heart (and we don't really care how far down that might be), it generates a native input event. Instead of catching that at each level and bubbling it up, we can let it bubble up naturally and catch it at the root of the custom-input component, and emit the required update:age event:

<custom-input :value="age" @input.native="$emit('update:age', $event.target.value)">

Putting it all together, we have two variables that are passed through components to input elements, two input event handlers, and no computeds.

new Vue({
  el: '#app',
  data: {
    name: 'Jerry',
    age: 21
  },
  components: {
    formView: {
      props: ['age', 'name'],
      components: {
        customInput: {
          props: ['value']
        }
      }
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
  <div>Name: {{name}}</div>
  <div>Age: {{age}}</div>
  <form-view :name.sync="name" :age.sync="age" inline-template>
    <div>
      <custom-input :value="age" @input.native="$emit('update:age', $event.target.value)" inline-template>
        <div>
          Age: <input :value="value">
        </div>
      </custom-input>
      <div>Name: <input :value="name" @input="$emit('update:name', $event.target.value)"></div>
    </div>
  </form-view>
</div>

Sign up to request clarification or add additional context in comments.

2 Comments

This looks like it will work, I'll try this and let you know.
A small addition. Passing an object in props is by reference, so if you set up a computed setter, you can modify the props variable directly from there. Perhaps not the best way of doing it, but thought it might be a noteworthy addition.

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.