It would be great if we could use v-bind with an object of attributes to pass props to a component.
<component is="component" v-bind="data"></component>
Currently we need to explicitly state the props we are passing to the component.
<component is="component" :prop-a="propA" :prop-b="propB"></component>
http://jsbin.com/yudivokovi/edit?html,js,output
Good idea! And another shorthand I'd like is to allow to skip the value, like the es6 object shorthand:
<component is="component" :prop-a :prop-b></component>
@sjoerdvisscher I'm not convinced about that one, while it's handy, it makes the template less readable. And I think Vue.js excels at readability.
I'm not against it, actually I really like it, it's sexy :dancer:, I want people to discuss about it
@janschoenherr Can't this be achieved with a custom directive?
This was possible with v-with
...back in the day. :calendar:
http://011.vuejs.org/api/directives.html#v-with
This feature will be very useful if component will be created programmatically and will have any number of props.
For now it possible to do it like this:
<component :is="comp"></component>
this.comp = Vue.extend(Object.assign({propsData: this.propsData }, componentDefinishion))
It is wrong solution, vue warns about it, but it works.
propsData may be initializer function in component definishion, same as data()
also dynamic component may operate with already initialized but unmounted instance
I create jsFilddle for detailed explanation
+1, it would be very useful, especially with some kind of a CMS, where all the relevant components would be sent with json asynchronically, and the whole Composite Tree would be built up at runtime with dynamic components.
I just spent some time confused by this, because the docs seem to indicate that it should work already!
http://vuejs.org/api/index.html#v-bind
When used without an argument, can be used to bind an object containing attribute name-value pairs. Note in this mode class and style does not support Array or Objects.
It works on elements, just not components (demo).
Would be great if this were implemented! (and, until then, the docs updated)
A use case beyond writing less code is writing a reusable mount()
function for use in unit tests:
const vm = mount(MyComponent, {
prop1: 'value1',
prop2: 'value2'
});
Currently having to write an individual mount function for every single component because of this lack of functionality :(
With Vue 2.0, thanks to vdom and the render function, it's pretty trivial to write a proxy component to accomplish this. I got this idea from @terrydai's solution for 1.0 on #3231.
Vue.component('component-proxy', {
props: {
name: {
type: String,
required: true
},
props: {
type: Object,
default: () => {}
}
},
render(createElem) {
return createElem(this.name, {
attrs: this.props
});
}
});
complete working example: http://jsbin.com/fifatod/5/edit?html,js,output
I believe this is the current behavior in 2.0 http://vuejs.org/api/#v-bind
Unless "attributes" is referring to only DOM attributes and not vue props, I'm not sure if that's the case.
This feature will be very helpful when porting react components to vue.
This feature works in Vue 2.x but not in latest 1.x as of today (even if documented)
See this fiddle: http://jsbin.com/kupataxopu/3/edit?html,js,output
and try changing library on top of HTML code.
I can't switch to Vue 2.x today for backward compatibility (primary for "v-model does not support dynamic input types" error, I've so many dynamic components), but I need this feature...
Thanks
@straps Does the code on the issue https://github.com/vuejs/vue/issues/3231 helps?
I thought I'd try my hand at fixing this for Vue 1.x but it looks like the v-bind
directive code is executed _after_ compileProps()
which is where the props values are populated. So I'm at a loss.
Any chance of seeing this in Vue 1.x? I think the current behavior should be considered a bug because the 1.x documentation states that it should be possible.
@jacobmischka: The documentation said that for 1.x, too - it's only for elements, not components. This feature request is valid in Vue 2, as well.
cc/ @posva
@callumacrae
It works on Vue 2: http://jsfiddle.net/posva/hkskbzry/
But it always better to make them explicit or use some kind of proxy component using a render
That's weird, I couldn't get it to work just now :/ will test again
EDIT: Was testing on the wrong version of Vue 😳 ignore me!
To receive object to a props in components you should define the type of that props to Object.
Like this:
`
props: {
profile: {
type: Object,
default: function () {
return {}
}
}
},
See the complete example.
https://jsfiddle.net/digitaldreams/z74v31k6/
this returns undefined.
default: () => {}
this returns an object literal.
default: () => ({})
the parser doesn't interpret the two braces as an object literal, but as a block statement. https://stackoverflow.com/a/28770578/493756
maybe this can help
https://jsfiddle.net/soetedja/jucwmm7L/
While just passing an object directly to v-bind might not be very readable, using es6 object shorthand can make it look very nice, imo.
Instead of:
<foo :prop1='prop1' :prop2='prop2' :prop3='prop3'></foo>
You can do:
<foo v-bind='{ prop1, prop2, prop3 }'></foo>
@jasonlfunk I was using v-bind="{prop1,prop2}"
but was having issues with IE 11.
[Vue warn]: Error compiling template:
- invalid expression: Expected ':' in {prop1,prop2}
- Raw expression: v-bind="{prop1,prop2}"
Am I missing an IE 11 package or something for this? It's not happening on any other browser. Seems odd to get a browser specific vue error like this.
Update : _False alarm_ Found out it's because that bind declaration is in our php file and not a vue/js file that's built out. Had to go about it a different, less clean, way.
parent making the components
<div is="house-card" v-for="house in houseList" v-bind:key="house.id" :house="house"></div>
the component receiving the props
<template>
<v-card>
<v-card-title>{{house.property_name}}</v-card-title>
</v-card>
</template>
<script>
import Vue from "vue";
export default {
name: "HouseCard",
props: ["house"]
};
</script>
<style>
</style>
This is really needed because my project stores form schemas in a database and render them using vue and being able to do the following with standard vue instead of custom directives would be great
<div v-for="(opt, key) in schema" :key="key">
<component :is="opt.name" v-bind="opt.attributes"></component>
</div>
What about functional components?
A hack is to use the internal $options
binding intended for static render functions, but ideally either this behavior should be documented or something that could augment the functional render context shall be provided.
And why not:
<template>
<AText :id="id" v-bind="$attrs">
<slot />
</AText>
</template>
<script lang="ts">
import Vue from 'vue'
import AText from '@/components/atoms/text/AText.vue'
export default Vue.extend({
name: 'AHeading',
components: {
AText
},
inheritAttrs: false,
props: {
id: {
type: String,
default: null
}
}
})
</script>
To be used like this:
<AHeading weight="bold">My Big Banana Heading 🍌</AHeading>
So no need to redefine the props in the parent component (AHeading), with type, default value, validator... No code duplication and adaptive if AText evolves.
What do you think about this?
you are amazing Killian Leroux. <3
Most helpful comment
With Vue 2.0, thanks to vdom and the render function, it's pretty trivial to write a proxy component to accomplish this. I got this idea from @terrydai's solution for 1.0 on #3231.
complete working example: http://jsbin.com/fifatod/5/edit?html,js,output