Vue: v-model support with functional components

Created on 22 May 2018  路  2Comments  路  Source: vuejs/vue

Version

2.5.16

Reproduction link

https://codesandbox.io/s/0mj5l70xwn

Steps to reproduce

Set two inputs with v-model, one directly and another using a functional component as wrapper.

What is expected?

The same binding behaviour on both inputs.

What is actually happening?

Only the standard input works, the functional component input doesn't get bind the value but it does get binded an input event with an unexpected behaviout.


The reason I would wrap an input into a functional component is to customize it look, while expecting vue to still apply all the v-model workarounds around it.

Most helpful comment

v-model is already supported in functional components, you need to do things manually (as with render functions) though:

export default {
  functional: true,
  render(h, { data, props }) {
    console.log(data)
    return h("input", {
      on: {
        input: e => data.on.input(e.target.value)
      },
      domProps: {
        value: props.value
      },
      attrs: {
        type: "text"
      }
    });
  }

(you can also use data.model)
See https://vuejs.org/v2/guide/render-function.html#v-model

All 2 comments

v-model is already supported in functional components, you need to do things manually (as with render functions) though:

export default {
  functional: true,
  render(h, { data, props }) {
    console.log(data)
    return h("input", {
      on: {
        input: e => data.on.input(e.target.value)
      },
      domProps: {
        value: props.value
      },
      attrs: {
        type: "text"
      }
    });
  }

(you can also use data.model)
See https://vuejs.org/v2/guide/render-function.html#v-model

Thank you for your answer @posva. I think we can work on a better balance between conveniance and low level features. There are a lot of edge cases covered by v-model that are getting lost. And I mean, a lot:

// input text
domProps: {
  "value": (value)
},
on: {
  "input": function($event) {
    if ($event.target.composing) return;
    value = $event.target.value
  }
}

// input radio 
domProps: {
  "checked": _q(value, null)
},
on: {
  "change": function($event) {
    value = null
  }
}

// input checkbox
domProps: {
  checked: Array.isArray(value) ? _i(value, null) > -1 : value
},
on: {
  change: function($event) {
    var $$a = value,
      $$el = $event.target,
      $$c = $$el.checked ? true : false;
    if (Array.isArray($$a)) {
      var $$v = null,
        $$i = _i($$a, $$v);
      if ($$el.checked) {
        $$i < 0 && (value = $$a.concat([$$v]));
      } else {
        $$i > -1 && (value = $$a.slice(0, $$i).concat($$a.slice($$i + 1)));
      }
    } else {
      value = $$c;
    }
  }
}

// input range
domProps: {
  "value": (value)
},
on: {
  "__r": function($event) {
    value = $event.target.value
  }
}

// select
on: {
  change: function($event) {
    var $$selectedVal = Array.prototype.filter
      .call($event.target.options, function(o) {
        return o.selected;
      })
      .map(function(o) {
        var val = "_value" in o ? o._value : o.value;
        return val;
      });
    value = $event.target.multiple ? $$selectedVal : $$selectedVal[0];
  }
}
...

And that code is not even including the v-model number, lazy and trim modifiers.

Low level rendering should not mean automatically loose all the conveniance. The v-model could set the domProps and events listeners workarounds on the data object as if it was a real input, because it is, and in my code I could choose to use those directly with the input, ignore it completely, or do some adjustments.

Perhaps there are some technical limitations I am ignoring here. Is that the case, @yyx990803?

Was this page helpful?
0 / 5 - 0 ratings