Interactive dropdowns

Posted 2 years ago by jediping

I've built my first Vue thing, which is three dropdowns, regions, districts, and stores. When you select a region, the region's districts show up. When you select the district, the stores show up. There may be a default value for any of these fields. I'd appreciate any thoughts on how I could improve this.

A couple of things I'd appreciate suggestions on:

  • I feel like I'm re-using a lot of code between the different selects. I've got to build a couple more sets of interactive dropdowns, and I know copy-paste is NOT the best way to go about it!
  • I'd like to figure out a better way to get any default values, in order to make this reusable. For example, instead of a Rule object, the value might be in a seachterms array.

HTML:

    <div id="app">
                        <div class="col-xs-4">
                            {!! Form::label('region_select',  trans("app.region_select")) !!}
                            <regions-select name="region" class="form-control" :regions="regions"></regions-select>
                        </div>
                        <div class="col-xs-4" v-if="districtShow">
                            {!! Form::label('district_select',  trans("app.district_select")) !!}
                            <districts-select name="district" class="form-control" :districts="districts"></districts-select>
                        </div>
                        <div class="col-xs-4" v-if="storeShow">
                            {!! Form::label('store_select',  trans("app.store_select")) !!}
                            <stores-select name="store" class="form-control" :stores="stores"></stores-select>
                        </div>
                    </div>

Script:

    var events = new Vue();

    Vue.component('regions-select', {
        props: ['regions'],
        template: `
            <select name="name" v-model="region">
                <option value="null">{{trans('app.region_select')}}</option>
                <option v-for="(region, index) in regions" :value="index">
                    @{{region}}
                </option>
            </select>
        `,
        data() {
            return {
                region: {!! json_encode(isset($rule) ? $rule->region_id : null) !!}
            }
        },
        watch: {
            region: function(val) {
                events.$emit('region-updated', {val});
            }
        }
    });

    Vue.component('districts-select', {
        props: ['districts'],
        template: `
            <select name="name" v-model="district">
                <option value="null">{{trans('app.district_select')}}</option>
                <option v-for="(district, index) in districts" :value="index">
                    @{{district}}
                </option>
            </select>
        `,
        data() {
            return {
                district: {!! json_encode(isset($rule) ? $rule->district_id : null) !!},
            }
        },
        watch: {
            district: function(val) {
                events.$emit('district-updated', {val});
            }
        }
    });

    Vue.component('stores-select', {
        props: ['stores'],
        template: `
            <select name="name" v-model="store">
                <option value="null">{{trans('app.store_select')}}</option>
                <option v-for="(store, index) in stores" :value="index">
                    @{{store}}
                </option>
            </select>
        `,
        data() {
            return {
                store: {!! json_encode(isset($rule) ? $rule->store_id : null) !!},
            }
        }
    });


    var app = new Vue({
        el: '#app',
        data: {
            regions: {!! json_encode($regions) !!},
            rule: {!! json_encode(isset($rule) ? $rule : null) !!},
            site: {!! json_encode($site) !!},
            districtShow: false,
            districts: [],
            storeShow: false,
            stores: [],
        },
        mounted() {
            if(this.rule != null) {
                this.region_id = this.rule.region_id;
                if(this.region_id != null) {
                    this.updateDistricts(this.region_id);
                }
                this.district_id = this.rule.district_id;
                if(this.district_id != null) {
                    this.updateStores(this.district_id);
                }
            }
            events.$on('region-updated', function(value) {
                app.updateDistricts(value.val);
            });
            events.$on('district-updated', function(value) {
                app.updateStores(value.val);
            });
        },
        methods: {
            updateDistricts(region_id) {
                this.districtShow = true;
                axios.get('/admin/ajax/getDistricts/' + this.site + '/' + region_id).then(response => this.districts = response.data);
                this.stores = [];
                this.storeShow = false;
            },
            updateStores(district_id) {
                this.storeShow = true;
                axios.get('/admin/ajax/getStores/' + this.site + '/' + district_id).then(response => this.stores = response.data);
            }
        }
    });

Please sign in or create an account to participate in this conversation.