0

Is possible to generate vue component using for loop. I am trying to generate and able to get but it's override by new component dynamically it's override component one schema also with component second with is at last generated.

https://jsfiddle.net/3ordn7sj/5/ https://jsfiddle.net/bt5dhqtf/973/

for (var key  in app.html) {
        Vue.component(key, {
        template: `<div><vue-form-generator :model="model"
        :schema="schema"
        :options="formOptions"
        ref="key"></vue-form-generator>{{ key }}</div>`,
        mounted() {
          this.schema = app.html[key]
        },
        data: function () {
          return {
            schema: app.html[key],
            key: '',
            formOptions: this.formOptions,
            model: this.model,
          }
        },
      }
    )
    }

Is possible to generate vue component using for loop. I am trying to generate and able to get but it's override by new component dynamically it's override component one schema also with component second with is at last generated. In above jsfiddel link my data is there inside created.

I am trying to generate vue component base on this data and I am using vue form generator.In above code what exactly I am trying to do is while my loop running form generated but I don't know how it's first component also getting second component schema and it;s showing on first step also overrides schema data.

I am very confused why this is happening I tried a lot but I am not getting any solution if you have please suggest what I can do for generate component using for loop inside function.

Please try to solve this issue or tell me id it;s not possible.

I did like this

<form-wizard @on-complete="onComplete"
                     @on-change="handleChange"
                     validate-on-back
                     ref="wizard"
                     :start-index.sync="activeTabIndex"
                     shape="circle" color="#20a0ff" error-color="#ff4949" v-if="html != 0">
            <tab-content v-for="tab in tabs"
                         v-if="!tab.hide"
                         :key="tab.title"
                         :title="tab.title"
                         :icon="tab.icon">
                <component :is="tab.component"></component>
            </tab-content>
        </form-wizard>

Inside Data I have added for now this tabs option

tabs: [{title: 'Personal details', icon: 'ti-user', component: 'firstTabSchema'},
                    {title: 'Is Logged In?', icon: 'ti-settings', component: 'secondTabSchema', hide: false},
                ],

generateNewForm.vue

<template>
    <div class="app animated fadeIn">
        <loading :active.sync="this.$store.state.isLoading"
                 :can-cancel="true"
                 :is-full-page="this.$store.state.fullPage"></loading>
        <b-row>
            <b-col cols="12" xl="12">
                <transition name="slide">
                    <b-card>
                        <div slot="header">
                            <b-button variant="primary" @click="goBack"><i class="icon-arrow-left icons font-1xl"></i>Back</b-button>
                        </div>

                        <formcomponent  :tree="this.$store.state.formData" />
                    </b-card>
                </transition>
            </b-col>
        </b-row>
    </div>
</template>
<script>
    import {store} from '@/components/store'
    import formcomponent from '@/components/formcomponent';
    import Vue from 'vue'
    import Loading from 'vue-loading-overlay';
    import 'vue-loading-overlay/dist/vue-loading.css';
    import {FormWizard, TabContent} from 'vue-form-wizard'
    import 'vue-form-wizard/dist/vue-form-wizard.min.css'
    import VueFormGenerator from "vue-form-generator";
    /*import VeeValidate from 'vee-validate';*/
    Vue.use(VueFormGenerator);
    Vue.use(Loading);

    export default {
        name: 'tables',
        store: store,
        data: () => {
            return {
                finalModel: {},
                activeTabIndex: 0,
                model: {},
                count: 0,
            }
        },
        components: {
            'loading': Loading,
            FormWizard,
            TabContent,
            formcomponent: formcomponent
        },

        created() {

        },
        beforeMount() {
            this.$store.dispatch('loadFormData', this.$route.params.id);
        },
        methods: {
            onComplete: function(){
                alert('Yay. Done!');
            },
            goBack() {
                this.$router.go(-1)
            }
        }
    }
</script>

formcomponent.vue

<template>
    <div>
        <form-wizard @on-complete="onComplete"
                     @on-change="handleChange"
                     validate-on-back
                     ref="wizard"
                     :start-index.sync="activeTabIndex"
                     shape="circle" color="#20a0ff" error-color="#ff4949" v-if="html != 0">
            <tab-content v-for="tab in tabs"
                         v-if="!tab.hide"
                         :key="tab.title"
                         :title="tab.title"
                         :icon="tab.icon">
                <component :is="tab.component"></component>
            </tab-content>
        </form-wizard>

    </div>
</template>

<script>
    import Vue from 'vue'
    import {FormWizard, TabContent} from 'vue-form-wizard'
    import 'vue-form-wizard/dist/vue-form-wizard.min.css'
    import VueFormGenerator from "vue-form-generator";

    //console.log(Vue.options);
    Vue.use(VueFormGenerator);
    export default {
        components: {
            FormWizard,
            TabContent,
        },
        data() {
            return {
                loadingWizard: false,
                error: null,
                count: 0,
                dash: '-',
                firstTime: 0,
                model: {},
                html: '',
                index: '',
                activeTabIndex: 0,
                tabs: [{title: 'Personal details', icon: 'ti-user', component: 'firstTabSchema'},
                    {title: 'Is Logged In?', icon: 'ti-settings', component: 'secondTabSchema', hide: false},
                ],
                formOptions: {
                    validationErrorClass: "has-error",
                    validationSuccessClass: "has-success",
                    validateAfterLoad: true,
                    validateAfterChanged: true,
                },
            }
        },
        created() {
            this.html = this.tree;
            this.index = this.ind;
        },
        props: ['tree', 'ind'],
        methods: {
            onComplete: function () {
                alert('Yay. Done!');
            },
            setLoading(value) {
                this.loadingWizard = value
            },
            handleChange(prevIndex, nextIndex) {
                console.log(`Changing from ${prevIndex} to ${nextIndex}`)
            },
            setError(error) {
                this.error = error
            },
            validateFunction: function () {

                return new Promise((resolve, reject) => {
                    console.log(this.$refs.firstTabSchema);
                    setTimeout(() => {
                        if (this.count % 2 === 0) {
                            reject('Some custom error')
                        } else {
                            resolve(true)
                        }
                        this.count++
                    }, 100)
                })
            },
            validate() {
                return true
            },
            buildTree(tree, rep = 1) {
                var html = '';
                var app = this;
                var dash = "--";
                app.html = tree;

                var test = this.formOptions;


                for (var key  in app.html) {
                    var isComponentExists = key in Vue.options.components
                    if(!isComponentExists) {
                    Vue.component(key, {
                            template: `<div :class="key"><vue-form-generator :model="model"
                                            :schema="schema"
                                            :options="formOptions"
                                            ref="key"></vue-form-generator>{{ key }}</div>`,
                            mounted() {
                               this.schema = app.html[key]
                               this.key = key
                            },
                            data: function () {
                                return {
                                    schema: app.html[key],
                                    key: '',
                                    formOptions: this.formOptions,
                                    model: this.model,
                                }
                            },
                        }
                    )
                    //console.log(Vue.$options);
                    this.$emit('init')
                    }
                }
            }
        },
        watch: {
            tree: {
                handler() {
                    this.html = '';
                    this.buildTree(this.tree)
                },
                deep: true
            }
        }
    }

</script>

2 Answers 2

1

So if I understand you correctly you are trying to use a list of some kind app.html to dynamically register a set of identical components under different names (key). I think it is possible, but i cannot tell from the code you provided what is going wrong.

I can tell you that this approach to code reuse/abstraction is probably not the right way to go. The whole point of components is that you can reuse functionality with the use of binding props. What you are trying to do is probably better achieved like this:

 Vue.component('my-custom-form', {
        props: ['key', 'schema', 'formOptions', 'model'],
        template: `
            <div>
              <vue-form-generator 
                :model="model"
                :schema="schema"
                :options="formOptions"
                :ref="key"
              ></vue-form-generator>{{ key }}
            </div>`,

})

Then in your vue template:

<my-custom-form
  v-for="(key, value) in app.html"
  :key="key"
  :schema="value"
  :formOptions="formOptions"
  :model="model"
/>

Let me know if that helps. Otherwise, if you are sure you want to stick with your original approach give me some more context for the code and I will see what i can do. Best of luck!

Sign up to request clarification or add additional context in comments.

3 Comments

Hello Thank You for response I am able to get form but issue is I am using form wizard as well and If I'll use this then I am not able to show step form.
when I am doing console.log(Vue.options) then inside components it's showing component loaded but it's override with last response. How we can resolve this isuue?
I have added code here can you please check. Thank You
0

I think i understand a little bit better where you are getting stuck. I see this piece of code in your jsfiddle:

<div id="app">
<div>
  <form-wizard @on-complete="onComplete">
    <tab-content v-for="tab in tabs"
                v-if="!tab.hide"
                :key="tab.title"
                :title="tab.title"
                :icon="tab.icon">
      <component :is="tab.component"></component>
    </tab-content>
  </form-wizard>
 </div>
</div>

You don't need to use the component :is syntax to solve this problem. You could also write is as follows:

<div id="app">
<div>
  <form-wizard @on-complete="onComplete">
    <tab-content v-for="(tab, tabindex) in tabs"
                v-if="!tab.hide"
                :key="tab.title"
                :title="tab.title"
                :icon="tab.icon">
      <my-custom-form v-if="tabindex == 1" :key="'the first key'" :schema="app.html['the first key']"/>
      <my-custom-form v-else-if="tabindex == 2" :key="'the second key'" :schema="app.html['the second key']"/>
    </tab-content>
  </form-wizard>
 </div>
</div>

etc. Let me know if that example is clear. best

4 Comments

but how I will pass key value and schema value if I don;t run loop for server data?
my intention is to generate dynamic form and there can be multiple steps not even 2 so I am not getting the way .
ok so make a computed value that maps over tabs and use it to bind the dynamic data you want to pass to your custom form to each tab element. This was just a simple example showing you you can do without the <component is: approach.
But how I can pass server data into this can you please suggest me so I can do or just show me example

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.