Vue: Do we have any way of using v-with like a two-way binding?

Created on 2 Oct 2014  ·  17Comments  ·  Source: vuejs/vue

I got a case where I need to update the $parent binding inside the component that is using it with v-with

All 17 comments

You can pass down an object and changes to that object will reflect on parent.

I have a component like this:

<div v-with="current_date: current_date">
   <input type="text" v-model="current_date">
</div>

Changes to current_date inside the component doesn't reflect on the parent, forcing me to do this:

created: function() {
  this.$watch("current_date", function(value) {
       this.$parent.current_date = value;
  });
}

The reason it doesn't reflect to parent is because if a component has isolated scope, it should avoid modifying its parent's state (and just take whatever data the parent gives it, so it's a unidirectional data flow). If it needs to access and modify parent state, then just make it inherit parent scope.

But then it would inherit too much, why this is a good pattern?

I'm not sure how big is your component - if that input field is all it's doing, why make it a component at all?

I would love to keep the behavior of v-with consistent with how arguments are passed into functions in JavaScript: you can't modify the original variable outside the function from within, you can only mutate an object that's been passed in.

makes sense

I used to create custom components behaving like form inputs using v-with.

E.g. I would have a switch component I could use like this:

<switch-input v-with='model: some.parentProperty' />
<file-uploader v-with='model: some.parentProperty' />

So the concept of keeping parent scopes untouched makes sense, except there seems no way to reproduce input-type behaviours using components.

I didn't find another way of doing this, would be great to have a way of using v-model on custom components. Any suggestions on how to do this with v0.11?

You can do v-with="model: some" then inside do v-model="model.someProperty", although maybe there could be a v-bind that does what the old v-with does...

If I use v-model="model.someProperty" inside the component template it's still gonna reference to the child property, which is only a clone.

Right now I'm manually watching for a value change and operating on the parent using this.$parent, which is quite a dirty one.

I'm not sure I understand the reasoning behind this change - the whole point of a VM* library that performs bi-directional binding is - to me - maintaining an accurate representation of decoupled data, not imposing hierarchical flow in the architecture.

...in JavaScript: you can't modify the original variable outside the function from within, you can only mutate an object that's been passed in...

Not sure I understand what you mean, E.g.:

// Root scope
var rootVariable = 'foo';

// Parent scope
(function () {
    var parentVariable = 'a';

    rootVariable = 'bar';

    // Child scope
    function foo () {
        parentVariable = 'b';
    }

    console.log(parentVariable); // 'a'
    foo();
    console.log(parentVariable); // 'b'
}());

console.log(rootVariable); // 'bar'

By that I mean this:

var rootVar = 1
var rootObj = { a: 1 }

function child (parentVal) {
  parentVal.a = 2
  parentVal = 2
}

child(rootVar)
console.log(rootVar) // 1
child(rootObj)
console.log(rootObj.a) // 2

So if you pass model down as an object, you can indeed mutate it from a child component. It's just you can't change the parent's reference to model.

Ok the example makes sense but I think in the context of a VM* library handling bi-directional binding is key, if you allow form inputs to manipulate the source of data components should have the same access to parent scopes.

I don't see a big difference between the semantics of a form input (Which comes as a pre-existing component of the library, which applies custom behaviour to a HTML tag) and a custom UI component - they should have the same level of access, right?

After some thinking I tend to agree the one-way restriction on v-with is unnecessary - this will likely be reverted in the next point release.

看到v-with重新支持双向实在太好了,我写了一些通用的component,比如日期选择,在一个form里可能多次调用,如果不能双向绑定的话,实在是不好处理。

<div class="form-control date" v-component="date" v-with="date:model.startDate"></div>
<div class="form-control date" v-component="date" v-with="date:model.endDate"></div>

@yyx990803 I had hugely appreciated that being reverted when this discussion took place, although I've noticed in has been reverted back again in newer versions.

The thing is, while the v-model directive is still escaping this logic (And not made re-adaptable to custom components), it's impossible now to create custom components that behave like form inputs by manipulating a referenced value in the parent scope.

Let's take the example of someone wanting to create an On / Off switch or a multiple choice with different markdown from a select.

Why is this:

<select v-model='myTwoWayValue'></select>

possible using default HTML inputs, while nothing like this:

<my-custom-switch value='myTwoWayValue'></my-custom-switch>

is not allowed?

I do understand the reasoning and philosophy behind a one directional data flow - but again, this approach doesn't really allow anyone to adopt different patterns, with the only exception of form inputs which still behave like two-way binding custom components and sort of escape this rule.

I don't mean to be annoying by re-opening this conversation, but since I'm still using Vue.js as I've been for very long time and I'm a great supporter, one of the things I always appreciated of it is its aspect of being unopinionated and versatile.

Vue.js presented from the start as a lightweight VM class that doesn't try to enforce upon you a monolithic architecture - allowing you to be truly modular in however you wish to structure tour application and escaping the framework hell / feature war.

This feels a bit like a step back into trying to impose a philosophy by limiting choice, which is really not what I'd expect from Vue.js.

Custom components can use v-model to work as native inputs. See the docs here: http://vuejs.org/guide/components.html#Form-Input-Components-using-Custom-Events

In essence:

  1. Your component accepts a value prop
  2. When the component's value changes, emit an input event with the new value: this.$emit('input', newValue)

Then, when the parent uses v-model on the component, the value updates.

Oh - I didn't spot that - guess I've pulled such an elaborate rant all for nothing - sorry @yyx990803 , this is actually quite a nice implementation (Still really liked the two way data binding syntax that has been present for a few sub versions, though).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

franciscolourenco picture franciscolourenco  ·  3Comments

seemsindie picture seemsindie  ·  3Comments

Jokcy picture Jokcy  ·  3Comments

hiendv picture hiendv  ·  3Comments

aviggngyv picture aviggngyv  ·  3Comments