jQuery - Linked Dropdown List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
$.fn.extend({
    // options: [{label: '', css: '', valueProperty: '', textProperty: '', selectedValue: '', childProperty: ''}, {...}]
    linkedDropdownList: function(data, options) {
        var _this = $(this);
        var id = _this.attr('id') + '_linkedDDL';
        var selectedObjects = [];
        var elFields = [];
        var elContainer = $('<div id="' + id + '"></div>');
        _this.append(elContainer);

        for(var i = 0; i < options.length; i++) {
            options[i].index = i;
            buildField(options[i]);
        }

        function buildField(option) {
            var elSelectId = id + '_' + option.index;
            var d = option.index === 0 ? data : selectedObjects[option.index - 1][options[option.index - 1].childProperty];
            if (!d || d.length === 0) {
                destroyField(option);
                return null;
            }

            var elField = $('<div class="form-group"><select id="' + elSelectId + '" class="form-control"></select></div>');
            if (option.label) {
                elField.prepend('<label for="' + elSelectId + '">' + option.label + '</label>');
            }
            if (option.css) {
                elField.addClass(option.css);
            }
            var elSelect = elField.find('select');
            selectedObjects[option.index] = d.length > 0 ? d[0] : null;
            for(var i = 0; i < d.length; i++) {
                var item = d[i];
                var elOption = $('<option value="' + (item[option.valueProperty]||'') + '">' + (item[option.textProperty]||'') + '</option>');
                if (option.selectedValue === item[option.valueProperty]) {
                    selectedObjects[option.index] = item;
                    elOption.prop('selected', true);
                }
                elSelect.append(elOption);
            } 
            elSelect.on('change', function() {
                option.selectedValue = $(this).val();
                for (var i = 0; i < d.length; i++) {
                    if (d[i][option.valueProperty] == option.selectedValue) {
                        selectedObjects[option.index] = d[i];
                    }
                }
                changeSelect(option);
            });
            elFields[option.index] = elField;
            elContainer.append(elField);
            return elField;
        }

        function rebindField(option) {
            var fieldData = option.index === 0 ? data : selectedObjects[option.index-1] ? selectedObjects[option.index-1][options[option.index-1].childProperty] : null;
            var elField = elFields[option.index];
            if (!elField) {
                elField = elFields[option.index] = buildField(option);
            }
            if (!elField) {
                destroyField(option);
                return;
            }

            var elSelect = elField.find('select');
            elSelect.find('option').remove();
            selectedObjects[option.index] = fieldData && fieldData.length > 0 ? fieldData[0] : null;
            if (fieldData && fieldData.length > 0) {
                for(var i = 0; i < fieldData.length; i++) {
                    var item = fieldData[i];
                    var elOption = $('<option value="' + (item[option.valueProperty]||'') + '">' + (item[option.textProperty]||'') + '</option>');
                    if (option.selectedValue === item[option.valueProperty]) {
                        selectedObjects[option.index] = item;
                        elOption.prop('selected', true);
                    }
                    elSelect.append(elOption);
                }
            } else {
                destroyField(option);
            }
        }

        function destroyField(option) {
            if (elFields[option.index]) {
                elFields[option.index].remove();
            }
            elFields[option.index] = null;
        }

        function changeSelect(option) {
            for(var i = option.index + 1; i < options.length; i++) {
                rebindField(options[i]);
            }
        }

        return {
            values: function() {
                var result = [];
                for(var i = 0; i < options.length; i++) {
                    result.push(elFields[i].find('select').val());
                }
                return result;
            },
        };
    }
});