Developing Vue applications with dynamic component insertion

Looking to develop a user-friendly form builder using Vue, where users can easily add different form fields by clicking buttons from a menu. If I only had one type of form field to add, it could be done like this (https://jsfiddle.net/u6j1uc3u/32/):

<div id="app">
  <form-input v-for="field in fields"></form-input>

  <button type="button" v-on:click="addFormElement()">Add Form Element</button>
</div>

<script type="x-template" id="form-input">
  <div>
    <label>Text</label>
    <input type="text" />
  </div>
</script>

In this case:

Vue.component('form-input', {
  template: '#form-input'
});

new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  },

  methods: {
    addFormElement: function() {
      this.fields.push({type: 'text', placeholder: 'Textbox ' + (++this.count)});
    }
  }
})

However, what if there are multiple types of form fields (input, file, select, etc.)? One approach could be creating different components for each type, but then how do we display multiple component types in a single list of form elements?

Is it possible to create a component with child components of different types based on the data in the fields array?

If you have any suggestions or better ways to tackle this problem while working with Vue, your guidance is greatly appreciated as I'm still new to learning Vue!

Answer №1

After exploring dynamic elements, I was able to piece together the following solution:

Vue.component('form-input', {
  template: '#form-input'
});

Vue.component('form-select', {
  template: '#form-select'
});

Vue.component('form-textarea', {
  template: '#form-textarea'
});

new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  },

  methods: {
    addFormElement: function(type) {
      this.fields.push({
        'type': type,
        id: this.count++
      });
    }
  }
})
<script src="[unique-link]"></script>
<div id="app">
  <component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>

  <button type="button" v-on:click="addFormElement('form-input')">Add Textbox</button>
  <button type="button" v-on:click="addFormElement('form-select')">Add Select</button>
  <button type="button" v-on:click="addFormElement('form-textarea')">Add Textarea</button>
</div>

<script type="x-template" id="form-input">
  <div>
    <label>Text</label>
    <input type="text" />
  </div>
</script>

<script type="x-template" id="form-select">
  <div>
    <label>Select</label>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</script>

<script type="x-template" id="form-textarea">
  <div>
    <label>Textarea</label>
    <textarea></textarea>
  </div>
</script>

Instead of creating a new form-input component for every item in the fields array, I am now generating a new component that corresponds to the correct component through the type property of the fields.

Answer №2

To create a dynamic form-input component in Vue, you can pass the field object as props. This allows you to change the type of input dynamically:

Vue.component('form-input', {
  template: '#form-input',
  props: ['field']
})

new Vue({
  el: '#app',
  data: {
    fields: [],
    inputType: '',
    count: 0
  },
  methods: {
    addFormElement(val) {
      this.fields.push({type: val, placeholder: 'Textbox ' + (++this.count)});
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <h3>Add form element</h3>
  <select size="3" v-model='inputType' @click="addFormElement(inputType)">
    <option value="text">Text</option>
    <option value="checkbox">Checkbox</option>
    <option value="radio">Radio</option>
  </select>
  <p>
    <form-input v-for="field in fields" :field="field"></form-input>
  </p>
</div>

<template id="form-input">
  <div>
    <label>{{ field.type }}</label>
    <input :type="field.type" />
  </div>
</template>

Answer №3

By examining the code provided in this response, it is evident that one can implement dynamic content for each form control element as well. The overall concept can be observed on this informative website:

   Vue.component('form-input', {
  template: '#form-input'
  , props: ['label','cnt']
   });

Vue.component('form-select', {
 template: '#form-select'
 , props: ['label','cnt']
});

Vue.component('form-textarea', {
   template: '#form-textarea'
   , props: ['label','cnt']
   });
new Vue({
  el: '#app',
  data: {
    fields: [],
    count: 0
  }
  , mounted() {
    // fetch those from back-end
    this.addFormElement('form-input','lbl', "form-input-content")
    this.addFormElement('form-textarea','lbl', "form-textarea-content")
    var select_cnt = [
      {'value': 1, 'text': 'item-01'},
      {'value': 2, 'text': 'item-02'}
    ]
    this.addFormElement('form-select','some-label',select_cnt)
  }
  , methods: {
    addFormElement: function(type,label,cnt) {
     this.fields.push({
       'type': type
       , id: this.count++
       , 'label':label
       , 'cnt':cnt
     });
   }
  }
})
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b7c1c2d2f7859982998681">[email protected]</a>/dist/vue.min.js"></script>
<div id="app">
 <component v-for="field in fields" v-bind:is="field.type" :key="field.id" :cnt="field.cnt" :label="field.label"></component>
</div>

<script type="x-template" id="form-input">
  <div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<input type="text" :value="cnt"/>
  </div>
</script>

<script type="x-template" id="form-textarea">
  <div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<textarea :value="cnt"></textarea>
  </div>
</script>

<script type="x-template" id="form-select">
  <div>
<label>Select</label>
<select>
  <option v-for="oitem in cnt" :value="oitem.value">{{oitem.text}}</option>
</select>
  </div>
  <div v-html="cnt"></div>
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to reverse engineer HTML, CSS, and JavaScript code into HTML format

Help needed! I am trying to edit the user interface but all the code is in one line and I can't figure out how to decompile it back to its original state. Can anyone offer assistance with this? <html lang="en"><head><meta char ...

The onClick event is not functioning properly with React's select and option elements

Looking for a way to get the option value from each region? const region = ['Africa','America','Asia','Europe','Oceania']; <div className="options"> <select> ...

TS2688 Error: Type definition file for 'tooltip.js' not found

Why am I getting an 'undefined' error when trying to import the Tooltip class from the npm tooltip.js package in my TypeScript file? ...

Discovering the Active Modal Form in BootStrap: Uncovering the Open Modal Form using JavaScript/jQuery

There are a total of 5 modal forms on my page. My goal is to identify the specific Id of the currently active one. One possible solution involves checking if $('#myModal').hasClass('in');. However, this method requires me to repeat the ...

Having trouble loading events on Fullcalendar.io?

Our team is utilizing fullcalendar.io and aiming to retrieve an event from our API controller. The Controller [Route("api/Bookings")] public class BookingApiController { // GET [HttpGet] public string Get() { ...

`Inconsistencies in state management across components`

Creating a calendar with the ability to add notes for each day is my main goal. The structure of my components is organized as follows: App component serves as the common component that renders the main Build component. The Build component utilizes CellBui ...

Step up Vue.js with Phonegap without the need for any pre-existing templates or frameworks

Looking for guidance as a beginner in Vue.js and Phonegap. Seeking assistance to integrate Vue.js with Phonegap without relying on any templates or frameworks. A basic example of listing will suffice. Grateful for any help provided. Thank you! ...

Having trouble sending data from a page to a child component using getStaticProps

I'm currently working on a project using next.js and I'm facing an issue with passing data from the "gymlist" page to the "table" component. Here is the code snippet from the "gymlist" page where I have defined the getStaticProps function: expor ...

Excessive Function Calls Detected in AngularJS Application

I'm facing a major performance issue. I need to display details in a list, but the function is being called excessively. Feel free to check out the demo here Here's the HTML code snippet : <div ng-controller="MyCtrl as ctrl"> <p>K ...

Using Django Crispy forms to dynamically hide fields based on the value of another field

What is the best way to dynamically hide or show a form field in Django crispy forms depending on the selected value of another field in the form? For example: Field A contains a dropdown menu with options '1' and '2'. Field B should ...

Trigger an Ajax function using a button within a Bootstrap modal

I need to trigger an ajax function after selecting an option from a bootstrap confirmation modal. The modal will appear by calling the remove(parameter) function. Any assistance would be greatly appreciated function remove(parameter){ // $("#remove-mod ...

Arranging a dropdown list of options in alphabetical order using Javascript

Could you assist me in sorting my select list alphabetically? Below is the code I currently have:- $.getJSON("php/countryBorders.geo.json", (data) => { $select.html(""); for (let i = 0; i < data["features"].leng ...

Getting rid of the <br> tag as well as the linked <span> element

I've been experimenting with creating dynamic forms. My latest project involves a text box, an 'Add' button, and a div. The idea is that whenever a user types something into the text box and clicks the Add button, that value should appear in ...

Invisible Thinglink image revealed upon resizing browser

I am currently repurposing a pre-existing theme that has a drop-down menu showcasing an image. I am attempting to integrate a Thinglink into the content section of this drop-down, but unfortunately, the image does not appear until I adjust the size of the ...

Can anyone suggest a solution to troubleshoot this issue with CSS Flexbox and absolute positioning?

I'm currently developing a React application featuring flex container cards (referred to as .FilmCard with movie poster backgrounds) within another flex container with flex-wrap. Each card has an item positioned absolutely (an FontAwesome arrow icon). ...

Error: JSON parsing failed due to an unexpected character 'W' at the beginning

I am encountering an issue while sending a POST Request through the API in JavaScript. The method I have been using for multiple POST Requests is now displaying the error message: SyntaxError: Unexpected token W in JSON at position 0 Below is the snippet ...

What could be causing this Angular controller to throw the error message "Error: Unknown provider: nProvider <- n"?

Check out the jsFiddle code here: <div ng-app=""> <div ng-controller="FirstCtrl"> <input type="text" ng-model="data.message" /> {{data.message + " world"}} </div> </div> function FirstCtrl($scope) { ...

What is the best way to integrate a Ruby object into JavaScript?

I'm attempting to integrate Ruby into the JS.erb file, where I need access to the @user object and its relationships. Instead of converting to a JSON object, I prefer the ERB to precompile on the server-side. My goal is to iterate in the JS file rat ...

What is the secret to remaining on the same spot even after the page is reloaded?

How can I maintain the AJAX call data after a page reload? I have attempted to use code that reloads the entire page, but I would like to stay in the same location. Is there a way to achieve this without reloading the entire page? $('#updateAddressPr ...

What are the steps for testing React components when they are wrapped by ThemeProvider/withStyle?

Is there a way to properly test a component that is wrapped with withStyle, as it seems the theme object does not pass through the component. Any suggestions on best practices for achieving this? I am considering using createShallow() and dive() methods t ...