ajameswolf
ajameswolf

Reputation: 1660

Vue.js nested for loop input field model binding

In this example I am allowing the user to create their own typed list of sections. Each type has it's own form fields. The form fields render properly however, if I enter data into one of the fields after I've created two duplicate sections, both inputs are updated with the typed in text. This is not the intended result.

Instead each section should update its form field data content individually and it should reflect back to the value stored within the data.section related to it.

What am I missing?

Laravel View

{{Form::open(['route' => 'api.post.store', 'class' => 'form-horizontal'])}}
    <fieldset>
        <div id="legend">
            <legend class="">Register</legend>
        </div>
        <div :key="section.id" v-for="(index,section) in sections" class="control-group form-group-lg">
            <div class="form-header">
                <h3>@{{ section.label }}</h3>
            </div>
            <pre>@{{ section | json }}</pre>
            <div v-for="field in section.fields" :key="field.id">

                <div class="text-field" v-show="field.inputType == 'text'">
                    <label class="control-label" :for="section.name">@{{ field.label }}</label>
                    <div class="controls">
                            <input v-model="field.data.content" class="input-xlarge form-control">
                        <p  class="help-block">@{{ field.helpText }}</p>
                    </div>
                </div>
                <div class="text-area-field" v-show="field.inputType == 'text-area'">
                    <label class="control-label" :for="section.name">@{{ field.label }}</label>
                    <div class="controls">
                        <textarea :v-bind="field.data.content" class="input xlarge form-control"  :placeholder="field.placeholder">
                            @{{ field.data.content }}
                        </textarea>
                    </div>
                </div>
                <div class="text-area-field" v-show="field.inputType == 'data-map'">
                    <label class="control-label" :for="section.name">@{{ field.label }}</label>
                    <div class="controls">
                        <textarea :v-bind="field.data.content" class="input xlarge form-control" :placeholder="field.placeholder">
                            @{{ field.data.content }}
                        </textarea>
                    </div>
                </div>
            </div>
        </div>

        <div class="control-group">
           <div class="controls">
               <div class="dropdown">
                   <a data-target="#" href="page.html" data-toggle="dropdown" class="dropdown-toggle">Dropdown <b class="caret"></b></a>
                   <ul class="dropdown-menu">
                       <li v-for="sectionType in sectionTypes">
                           <a @click="setSectionCreateType(sectionType)" href="#">@{{ sectionType.label }}</a>
                       </li>
                   </ul>
               </div>
           </div>
            <div class="controls">
                <div @click="addSection()" class="btn bdn-success"  class="btn btn-success">Add Section</div>
            <div @click="savePost()" class="btn bdn-success"  class="btn btn-success">Save</div>

        </div>
        </div>
    </fieldset>
{{Form::close()}}

Vuefile

<script type="text/javascript">
    import Vue from 'vue';
    import FormField from './create/FormField.vue';
    export default {
        components: {
            FormField,
        },
        ready: function () {

        },
        filters: {},
        data(){
            return {
                messages: [],
                sections: [],
                saveSections: [],
                sectionCreateType: false,
                sectionTypes: [
                    {
                        label: 'Company',
                        map: 'company',
                        fields: [
                            {
                                label: 'name',
                                name: 'name',
                                inputType: 'text',
                                placeholder: 'Company Name',
                                data: {
                                    content: '',
                                },
                            },
                            {
                                label: 'symbol',
                                name: 'symbol',
                                inputType: 'text',
                                placeholder: 'stock symbol',
                                data: {
                                    content: '',
                                },
                            }
                        ]

                    },
                    {
                        label: 'Link',
                        map: 'link',
                        inputType: 'text',
                        data: {},
                        fields: [
                            {
                                label: 'url',
                                name: 'url',
                                inputType: 'text',
                                placeholder: 'Url',
                                data: {
                                    content: '',
                                },
                            },
                        ]

                    },
                    {
                        label: 'Paragraph',
                        map: 'paragraph',
                        data: {},
                        fields: [
                            {
                                label: 'content',
                                name: 'content',
                                inputType: 'text-area',
                                placeholder: 'Content',
                                data: {
                                    content: '',
                                },
                            },
                        ]
                    },

                    {
                        label: 'Person',
                        map: 'person',
                        data: {},
                        inputType: 'data-map',

                        'fields': [
                            {
                                label: 'first_name',
                                name: 'name',
                                placeholder: 'Person Name',
                                data: {
                                    content: '',
                                },
                            },
                            {
                                label: 'last_name',
                                name: 'name',
                                placeholder: 'Person Name',
                                data: {
                                    content: '',
                                },
                            }
                        ]

                    },
                ],


            }


        },
        directives: {},
        events: {},
        methods: {
            setSectionCreateType(type)
            {
                console.log('setting sectionCreateType: ' + type.label)

                this.sectionCreateType = type;
            },
            addSection()
            {
                if (!this.sectionCreateType) {
                    this.sectionCreateType = this.sectionTypes[0];

                }
                this.createSection(this.sectionCreateType);
            },
            createSection(type)
            {
                this.sections.push(Vue.util.extend({}, type))

            },
            previewPost(){
            },
            savePost: function(){
                var view = this;
                var saveObject = [];
                var sectionObject = [];


                this.sections.forEach(function (section) {



                    if(!sectionObject[section.type.map])
                    {
                    sectionObject[section.type.map] = [];
                    }

                    for (var key in section.type.fields) {
                        var field = section.type.fields[key];
                        var saveKey = [];
                        saveKey[field.name] = field.data.content;
                    }
                    sectionObject[section.type.map].push(saveKey);

                });
                saveObject.push(sectionObject);
                console.log(saveObject);

            },
        }


    }

</script>

Upvotes: 0

Views: 3482

Answers (1)

Marek Urbanowicz
Marek Urbanowicz

Reputation: 13634

You are using the same v-model so VueJS does what it should do. You have to create e.g. list of models and somehow handle index (e.g. take it from v-for for every section/subsection and use v-model='list[index].field

Upvotes: 3

Related Questions