Dynamic Component With Cloning Example Vue.js
Nowadays, web developers prefer components to build the web pages effectively. Splitting the UI into reusable pieces is the goal of component creation. Each component will render specific predefined HTML design. There is no problem when the component is static.
But sometimes based on condition or scenario, we have to render different components dynamically. To achieve this without using routing, Vue.js provides a special feature for us – Dynamic Components. Let’s take a deep dive to understand it clearly. If you are new to Vue.js Component topics, you can read about Components in Vue 3 and Single File Components Vue 3 before moving to this session.
Dynamic Component With Cloning Example Vue.js
In the below example, we can dynamically change the component. Here the old component will unmount and the new component will mount when the changes are made.
<!-- Syntax -->
<!-- component changes when componentName changes -->
<component :is="componentName"></component>
We have to use is
attribute with component
tag to achieve dynamic component features in Vue.js. Note that, here when we change the componentName
the new component will render.
Dynamic Component With Native HTML elements
We can use is
attribute with native HTML elements. When we bind an element to is
attribute, it will render the HTML element in the DOM.
<component :is="'button'">This is Button</component>
// This will show a button
In addition, we can use the Vue.js component inside the HTML element using is
attribute. In the below example, we are using my-row
component inside the table HTML element
<table>
<tr is="vue:my-row"></tr>
</table>
keep-alive with Dynamic Component
Sometimes when we switch the components, we need to maintain the old component state or need to avoid the re-render process. Which means, we want to cache the component states. To achieve this, Vue.js provides a keep-alive feature. We can use it as below to cache the component states,
<!-- components will be cached! -->
<keep-alive>
<component :is="componentName"></component>
</keep-alive>
Dynamic Component With Cloning Example Vue.js
Generally in Vue.js we can use a for
loop to clone a single component. Dynamic components along with a for loop helps us to clone different types of components at a go. Firstly we are going to create components for button, input and text-area.
DcButton.vue
<template>
<button class="btn">
{{ label }}
</button>
</template>
<script>
export default {
props: {
label: {
type: String,
default: "Default",
},
},
setup() {
return {};
},
};
</script>
<style scoped>
.btn {
background-color: #4999f5;
border: none;
color: white;
padding: 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 2px 2px;
cursor: pointer;
}
.btn:hover {
background-color: #0417c0;
color: white;
}
</style>
DcInput.vue
<template>
<div>
<input
type="text"
class="input"
v-model="value"
:placeholder="placeHolderLabel"
/>
</div>
</template>
<script>
export default {
props: {
placeHolderLabel: {
type: String,
default: "Enter the value",
},
},
data() {
return {
value: "",
};
},
};
</script>
<style scoped>
.input {
width: 200px;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
</style>
DcTextArea.vue
<template>
<div>
<textarea
v-model="value"
rows="3"
cols="3"
class="input"
:placeholder="placeHolderLabel"
/>
</div>
</template>
<script>
export default {
props: {
placeHolderLabel: {
type: String,
default: "Enter the value",
},
},
data() {
return {
value: "",
};
},
};
</script>
<style scoped>
.input {
width: 200px;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
</style>
Secondly, we are going to create a dynamic component using the component
tag. Note that, here we have two props namely componentName
, componentProps
. So whenever we pass the component name to this component it will render the specific component. We can also provide props
for our component at runtime. So let’s do it.
DynamicComp.vue
<template>
<component :is="componentName" v-bind="componentProps"></component>
</template>
<script>
export default {
props: {
componentName: String,
componentProps: Object,
},
};
</script>
Since we are going to use input and text area components dynamically, we have to add the same with app component in main.js as follows,
import { createApp } from "vue";
import router from "./router/router.js";
import App from "./App.vue";
import dcInput from "./components/dynamic-comp/DcInput"
import dcTextArea from "./components/dynamic-comp/DcTextArea"
let app = createApp(App);
app.component("dcInput",dcInput)
app.component("dcTextArea",dcTextArea)
app.use(router).mount("#app");
Now we are going to use the above components to create a simple cloning example. Here we are using two methods namely addInput
, addTextArea
to add input and text area components respectively.
DyanamicComponentDemo.vue
<template>
<h1>Simple Cloning Component Example</h1>
<div class="grp">
<dcButton label="Add Input" @click="addInput" />
<dcButton label="Add Text Area" @click="addTextArea" />
</div>
<dynamicComp
v-for="(item, index) in items"
:key="index"
:componentName="item.componentName"
:componentProps="item.componentProps"
>
</dynamicComp>
</template>
<script>
import { ref } from "@vue/reactivity";
import dynamicComp from "../components/dynamic-comp/DynamicComp.vue";
import dcButton from "../components/dynamic-comp/DcButton.vue";
export default {
components: {
dynamicComp,
dcButton,
},
setup() {
let items = ref([]);
const addInput = () => {
items.value.push({
componentName: "dcInput",
componentProps: {
placeHolderLabel: "Cloning Input",
},
});
};
const addTextArea = () => {
items.value.push({
componentName: "dcTextArea",
componentProps: {
placeHolderLabel: "Cloning Text Arae",
},
});
};
return {
items,
addInput,
addTextArea,
};
},
};
</script>
<style scoped>
.grp {
padding-left: 408px;
}
</style
In the above example, we are using a dynamic component with a for
loop to clone different components. so whenever we update the items, it will create the new component dynamically. The thing is we have to push the component name and props to items as we did in addInput, addTextArea methods. You can find the full working example below,
Dynamic Component With Cloning Example Vue.js
Full Sources
- https://github.com/programeasily/vue-3-basics/tree/main/src/components/dynamic-comp
- https://github.com/programeasily/vue-3-basics/blob/main/src/page/DynamicComponentDemo.vue
Reference
- https://v3.vuejs.org/guide/list.html#mapping-an-array-to-elements-with-v-for
- https://v3.vuejs.org/api/special-attributes.html#is
- https://v3.vuejs.org/guide/component-dynamic-async.html#dynamic-components-with-keep-alive
Summary
- We can render different components dynamically using component tag.
- The old component will unmount and the new component will mount when the changes are made.
- when we bind HTML elements to
is
attribute in the component tag, it will render the same in the DOM. - We can use dynamic components with a
for
loop to clone different types of components at a go.