I want to display a component depending on it's type. Let me explain.
I have multiple components that are similar to each other but depending on the given type they should display something different. With the defineAsyncComponent
method I can import the components and use them easiliy. Example:
const CheckboxControl = defineAsyncComponent(
() => import('@/components/editor/controls/CheckboxControl.vue'),
);
This works fine, but if I do this I have a ton of imported components. I don't want this. My approach is to wrap the defineAsyncComponent
inside an arrow function like this:
const loadComponent = async (type: string) =>
defineAsyncComponent(
() =>
import(
`@/components/editor/controls/${type[0].toUpperCase()}${type.substring(
1,
)}Control.vue`
),
);
In the template I am then able to render the component like this <component :is="renderComponent(control.type)" />
But this gives me the following warning:
[Vue warn]: Component is missing template or render function.
Awaiting the defineAsyncComponent
method doesn't solve the issue.
What am I doing wrong? How can I dynamically import these components?
Update
Here are all the possibilities that can be inside the control.type
attribute:
- checkbox
- date
- number
- radio
- range
- select
- textarea
- text
Update 2
This is my current code that is working:
const CheckboxControl = defineAsyncComponent(
() => import('@/components/editor/controls/CheckboxControl.vue'),
);
const DateControl = defineAsyncComponent(
() => import('@/components/editor/controls/DateControl.vue'),
);
const EmailControl = defineAsyncComponent(
() => import('@/components/editor/controls/EmailControl.vue'),
);
const NumberControl = defineAsyncComponent(
() => import('@/components/editor/controls/NumberControl.vue'),
);
const RadioControl = defineAsyncComponent(
() => import('@/components/editor/controls/RadioControl.vue'),
);
const RangeControl = defineAsyncComponent(
() => import('@/components/editor/controls/RangeControl.vue'),
);
const SelectControl = defineAsyncComponent(
() => import('@/components/editor/controls/SelectControl.vue'),
);
const TextareaControl = defineAsyncComponent(
() => import('@/components/editor/controls/TextareaControl.vue'),
);
const TextControl = defineAsyncComponent(
() => import('@/components/editor/controls/TextControl.vue'),
);
const loadComponent = (type: string) => {
switch (type) {
case 'checkbox':
return CheckboxControl;
case 'date':
return DateControl;
case 'email':
return EmailControl;
case 'number':
return NumberControl;
case 'radio':
return RadioControl;
case 'range':
return RangeControl;
case 'select':
return SelectControl;
case 'textarea':
return TextareaControl;
case 'text':
return TextControl;
default:
// TODO: show error component if type not supported
break;
}
};
CodePudding user response:
Thanks @Estus Flask for your help :)
So the problem was that I was trying to import it with the @
alias. I changed my method to this:
const loadComponent = (type: string) =>
defineAsyncComponent(
() =>
import(
`./controls/${type[0].toUpperCase()}${type.substring(1)}Control.vue`
),
);
This works now.
I don't know why in this case it is not working with the @
alias, because it works when I use it in
const CheckboxControl = defineAsyncComponent(
() => import('@/components/editor/controls/CheckboxControl.vue'),
);
Maybe someone has an explanation to this?
CodePudding user response:
async
forces the function to return promise object, while a component is expected. It should be regular function:
const loadComponent = (type: string) => ...
It's defineAsyncComponent
that handles underlying promise from import
.