[Vuejs]-Laravel, VueJS – keeping 2 arrays in sync while dragging & dropping

0πŸ‘

βœ…

I’ve kept this open for 17d and have been working the issue. I’m posting the solution I’ve come up with to help anyone else who might run into this in the future AND/OR to prompt anyone with any better ideas that might be more efficient.

I refactored the code to manage the display of the checkboxes in this snippet of template code:

            <div class="form-group">
                <div v-for="item in checkbox_list" class="col-sm-2" style="text-align: center">
                    <label class="control-label">@{{ item.value }}</label>
                    <a v-if="item.instr" data-toggle="tooltip" :title="item.instr" data-placement="top">
                        <i class="fas fa-info-square purple"></i>
                    </a>
                </div>
            </div>
            <div class="form-group">
                <div v-for="item in checkbox_list" class="col-sm-2">
                    <input type="checkbox" class="form-control input-sm" v-model="choices"
                           :id="item.id"
                           :value="item.value"
                           :name="item.id">
                </div>
            </div>

My Vue code is as follows:

    new Vue({
        el: '#el',
        data: {
            admin_props: @json($admin_props),
            separator: '{{ $org_props[0]->value }}',
            header: '{{ $org_props[1]->value }}',
            choices: [],
            drag: false,
            checkbox_list: [
                {sort: 0, checked: 0, value: "@lang('messages.fields.category')", id: "category", instr: '@lang('messages.admin.api.api_info_cat')'},
                {sort: 0, checked: 0, value: "{!! trans_choice('messages.headers.et', 1) !!}", id: "et", instr: '@lang('messages.admin.api.api_info_et')'},
                {sort: 0, checked: 0, value: "@lang('messages.admin.api.api_times')", id: "api_times"},
                {sort: 0, checked: 0, value: "@lang('messages.headers.pdu_detail')", id: "pdu_detail"},
                {sort: 0, checked: 0, value: "@lang('messages.fields.memprice')", id: "memprice"},
                {sort: 0, checked: 0, value: "@lang('messages.fields.nonprice')", id: "nonprice"},
            ],
        },

        mounted: function () {
            this.choices = this.admin_props[1].value.split(' ' + this.separator + ' ',);
            this.varArray_update();
        },

        watch: {
            choices: function () {
                this.admin_props[1].value = this.choices.join(' ' + this.separator + ' ');
                this.api_update('header', this.admin_props[1].value);
                this.varArray_update();
            }
        },
        methods: {
            api_update: function (name, value) {

                axios.post('/panel/update', {
                    name: name,
                    value: value,
                })
                    .catch(error => console.log(error.response));
            },

            varArray_update: function() {
                var index = 0;
                this.checkbox_list.forEach(e => {
                    e.checked = 0;
                    e.sort = 0;
                });

                this.choices.forEach(element => {
                    index += 1;
                    console.log(index, element);
                    var x = this.checkbox_list.filter(function(ele) {
                        if(ele.value == element) {
                            ele.checked = 1;
                            ele.sort = index;
                        }
                    });
                });
                var out = [];
                var array_copy = this.checkbox_list;
                array_copy = array_copy.filter(function(v){ return v.checked == 1; });
                array_copy.sort((a, b) => (a.sort > b.sort) ? 1 : -1);
                array_copy.forEach(function(v) { out.push(v.id); });
                var id_hdr = out.join(this.separator);
                this.api_update('var_array', id_hdr);
            },
        }
    });

The choices array is auto-managed by the Vue package for sortable and when it’s updated via the drag/drop UI, the sort order and such is getting maintained (as expected).

Because I needed to replicate that with corresponding variable names associated with the display names, I set up the checkbox_list object to store the name/value pairs and added on a checked state, sort order and instr (instruction text only used during the initial setup of the display)

I have a watch setup on choices such that it updates both the header (used for display) and the checkbox_list array. I then manipulate a copy of that array to get down to an array of variable names that is sorted according to the corresponding display values in choices.

If there is a more efficient way to do this, I would love to hear about it.

Leave a comment