Dynamic Component With Cloning Example Vue.js

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

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

Reference

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.

Leave a Reply

%d bloggers like this: