Dynamic components with dynamic unknown binds

Hi, I’m trying to achieve something like this:

<component :is="someComp" v-bind="compProps" :someProp="someValue"></component>

So far so good…except for any bindings, events and such, which would be unknown (as well as props and attrs) so I can’t hardcode it into the template (as in the example above).

I guess I’m trying to achieve something like this:

(everything in an object defined somewhere else, retrieved from a server, etc)

{ prop1: 'foo1', prop2: 'foo2', ':class': 'item.class', }

But of course v-bind with an object only works for props and attrs.

So far I’ve tried:

  1. v-bind: as stated above, only works for props and attrs
  2. a custom directive: creating any corresponding vnodes and attaching them, couldn’t manage to actually append any child vnodes
  3. an async component, but of course, by the time of defining it’s template, I don’t have any props nor attrs to actually do anything interesting

Also, about point 2, a custom directive and/or working with the virtual DOM, I don’t know how complex or not any binding expressions might be, so having to parse and apply them manually is kinda reinventing the wheel…

How to achieve something like this ?
What’s the best/propper/elegant way to achieve this?


Update: I’ve managed to do this through a custom component that wraps an async custom component, which gave me (initially) the same issue of not having props to know what should be the template for the async comp, but by chance discovered that I could hook myself into “beforeCreate” (on the static comp) and there define the async comp (instead of defining it directly in the “components” option of the Component Options object, and it worked just perfectly…

But I’m not sure if this is actually the propper way to achieve this, it works marvelously, but feels kinda hacking my way around rather than “the Vue way to do this”…

Any thoughts?

Can you provide your code? Without that it’s hard to advise.

export default {
props: {
	compo: Object,
	item: Object,
},

template: '<temp-async></temp-async>',

beforeCreate()
{
	var ctx = this;
	this.$.components = {
		'temp-async': defineAsyncComponent(() => new Promise((resolve, reject) => {
			var template = `<${this.compo.type} `;
			if(this.compo.props != undefined)
			for(var x in this.compo.props)
				template += ` ${x}="${this.compo.props[x]}"`

			template += `></${this.compo.type}>`;
        
			resolve({
				template: template,
				data(){
					return {
						__ITEM: ctx.$props.item,
					}
				},
			})
		}))
	};
},

}

so what are you missing ? is it just events ?

you can bind an object to v-on (vue 2.4+) or use dynamic names (vue 2.6+) :

<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
<button v-on:[event]="doThis"></button>
<button @[event]="doThis"></button>

Yes, of course.
But problem here is that everything would be unknown.
Comp name, props, attrs, binds, events…everything, if any, is unknown and defined in a JSON object (let’s say) fetched from server.

Dynamic components (seem to be) the solution for this, you get to tell it dynamicaly which component to use, and you can give it an object with props…but (again) what if I need to define unknown events, react binds or whatever else?

You can use v-bind to bind (unknown) props and attrs, but any reactivity needs to be hardcoded into the template, or manually parsed and implemented (let’s say on a render() function), which feels a little like an overkill, like using a nuke to bake a cake.

So, again, I want to turn this:

<component :is="someComp" v-bind="compProps" :someReactiveProp="someValue"></component>

into just this:

<component :is="someComp" v-bind="compEverything"></component>

(notice that it’s missing the :someReactivePropbind)

And (again) after a whole week of just starting with Vue and looking at each and every approach to “dynamic comps”, I managed to do this through a (so called of my own component) “proxy-comp” that actually wraps an async comp, that only on “beforeCreate” (from proxy-comp) actually defines that async comp template and everything works just great.

But the question remains the same, what’s the best way to achieve something like this? Googled all around for a week, and kinda feels like I came around a solution to something everyone seems to be trying to achieve.

PS: I’m using this solution right now to present fully unknown comps with binds and all, but also refactored my code to another custom comp “raw-template” that does just the same but instead of taking an object of props, attrs, binds, whatever, just takes a fully valid-Vue template (through a string)

and when I say “feels like using a nuke to bake a cake”, I mean…imagine that I’m my definitions object I use something like this:

{
onClick: //something
}

Then I would need to (probably through a render() function) place an event listener, that in turn will have to eval() the code (string) provided on the object, etc etc etc etc.

Now multiply that to infinity of whatever someone may put into that object, then multiply that to the whole extension and power of Vue…and I would be having to (essentially) create a scripting language of my own inside Vue itself…

A much better solution would be to find a way to dynamically assign “Vue stuff” and let Vue solve it itself…

And (again and again), the only way I found around this is using an async comp BUT wrapped in another comp, and only defined on the “beforeCreate” hook of said last comp, otherwise, whether I use an async comp or not, I don’t get to know anything (for instance, comp name) and I’m still stuck with a static template.


Once more, at first, I was hyped with a custom render function and using the h() function to create nodes to render…also very hyped with the withDirectives() associated function…but, again, core directives (like bind) don’t work with withDirectives() so it wasn’t that much of a solution in the end…

So it ends up being a double question…

What’s the best way to achieve a “everything dynamic” situation?

And if injecting a template in a way is the propper answer, then what’s the best way to perform said injection?

<component :is="someComp" v-bind="compProps" :someReactiveProp="someValue" />
is equivalent to
<component :is="someComp" v-bind="{ ...compProps, someReactiveProp: someValue }">

Yes yes, but nothing other than just props and attrs work with v-bind…

But what about directives? Any of them, particularly the case of the core ones (like v-on, v-for, etc) ?