UNPKG

dependent-dropdown

Version:

A multi level dependent dropdown JQuery plugin that allows nested dependencies.

299 lines (287 loc) 12.2 kB
/*! * dependent-dropdown v1.4.9 * http://plugins.krajee.com/dependent-dropdown * * Author: Kartik Visweswaran * Copyright: 2014 - 2019, Kartik Visweswaran, Krajee.com * * Licensed under the BSD-3-Clause * https://github.com/kartik-v/dependent-dropdown/blob/master/LICENSE.md */ (function (factory) { "use strict"; //noinspection JSUnresolvedVariable if (typeof define === 'function' && define.amd) { // jshint ignore:line // AMD. Register as an anonymous module. define(['jquery'], factory); // jshint ignore:line } else { // noinspection JSUnresolvedVariable if (typeof module === 'object' && module.exports) { // jshint ignore:line // Node/CommonJS // noinspection JSUnresolvedVariable module.exports = factory(require('jquery')); // jshint ignore:line } else { // Browser globals factory(window.jQuery); } } }(function ($) { "use strict"; $.fn.depdropLocales = {}; var $h, DepDrop; // global helper object $h = { isEmpty: function (value, trim) { return value === null || value === undefined || value.length === 0 || (trim && $.trim(value) === ''); }, setParams: function (props, vals) { var out = {}; if (props.length === 0) { return {}; } $.each(props, function (key, val) { out[val] = vals[key]; }); return out; }, toStr: function(str) { return $h.isEmpty(str) ? str : str.toString(); } }; DepDrop = function (element, options) { var self = this; self.$element = $(element); $.each(options, function (key, value) { self[key] = value; }); self.initData(); self.init(); }; //noinspection JSUnusedGlobalSymbols DepDrop.prototype = { constructor: DepDrop, initData: function () { var self = this, $el = self.$element; self.initVal = $el.val(); self.initDisabled = $el.attr('disabled'); $el.data('url', self.url) .data('placeholder', self.placeholder) .data('loading', self.loading) .data('loadingClass', self.loadingClass) .data('loadingText', self.loadingText) .data('emptyMsg', self.emptyMsg) .data('params', self.params); }, init: function () { var self = this, i, depends = self.depends, $el = self.$element, len = depends.length, chkOptions = $el.find('option').length, initDepends = self.initDepends || self.depends; if (chkOptions === 0 || $el.find('option[value=""]').length === chkOptions) { $el.attr('disabled', 'disabled'); } for (i = 0; i < len; i++) { self.listen(i, depends, len); } if (self.initialize === true) { for (i = 0; i < initDepends.length; i++) { $('#' + initDepends[i]).trigger('depdrop:change'); } } $el.trigger('depdrop:init'); }, listen: function (i, depends, len) { var self = this; $('#' + depends[i]).on('depdrop:change change select2:select krajeeselect2:cleared', function (e) { var $select = $(this); if (!$h.isEmpty($select.data('select2')) && e.type === 'change') { return; } self.setDep($select, depends, len); }); }, setDep: function ($elCurr, depends, len) { var self = this, $el, type, j, value = {}; for (j = 0; j < len; j++) { $el = $('#' + depends[j]); type = $el.attr('type'); value[j] = (type === "checkbox" || type === "radio") ? $el.prop('checked') : $el.val(); if (self.skipDep && (value[j] === self.loadingText || value[j] === '')) { self.$element.html('<option id="">' + self.emptyMsg + '</option>'); return; } } self.processDep(self.$element, $elCurr.attr('id'), value, depends); }, processDep: function ($el, vId, vVal, vDep) { var self = this, selected, optCount = 0, params = {}, settings, i, ajaxData = {}, vUrl = $el.data('url'), paramsMain = $h.setParams(vDep, vVal), paramsOther = {}, key, val, vDefault = $el.data('placeholder'), vLoad = $el.data('loading'), vLoadCss = $el.data('loadingClass'), vLoadMsg = $el.data('loadingText'), vNullMsg = $el.data('emptyMsg'), vPar = $el.data('params'); self.ajaxResults = {}; ajaxData[self.parentParam] = vVal; if (!$h.isEmpty(vPar)) { for (i = 0; i < vPar.length; i++) { key = vPar[i]; val = $('#' + vPar[i]).val(); params[i] = val; paramsOther[key] = val; } ajaxData[self.otherParam] = params; } ajaxData[self.allParam] = $.extend(true, {}, paramsMain, paramsOther); settings = { url: vUrl, type: 'post', data: ajaxData, dataType: 'json', beforeSend: function (jqXHR) { $el.trigger('depdrop:beforeChange', [vId, $("#" + vId).val(), self.initVal, jqXHR]); $el.find('option[selected]').removeAttr('selected'); $el.val('').attr('disabled', 'disabled').html(''); if (vLoad) { $el.removeClass(vLoadCss).addClass(vLoadCss).html('<option id="">' + vLoadMsg + '</option>'); } }, success: function (data, textStatus, jqXHR) { self.ajaxResults = data; selected = $h.isEmpty(data.selected) ? (self.initVal === false ? null : self.initVal) : data.selected; if ($h.isEmpty(data)) { self.createOption($el, '', vNullMsg, ''); } else { self.renderSelect(data.output, vDefault, selected, $el); if ($el.find('optgroup').length > 0) { $el.find('option[value=""]').attr('disabled', 'disabled'); } if (data.output && !self.initDisabled) { $el.removeAttr('disabled'); } } optCount = $el.find('option').length; if ($el.find('option[value=""]').length > 0) { optCount -= 1; } $el.trigger('depdrop:change', [vId, $("#" + vId).val(), optCount, self.initVal, textStatus, jqXHR]); }, error: function (jqXHR, textStatus, errThrown) { $el.trigger('depdrop:error', [vId, $("#" + vId).val(), self.initVal, jqXHR, textStatus, errThrown]); }, complete: function (jqXHR, textStatus) { if (vLoad) { $el.removeClass(vLoadCss); } $el.trigger('depdrop:afterChange', [vId, $("#" + vId).val(), self.initVal, jqXHR, textStatus]); } }; $.extend(true, settings, self.ajaxSettings); $.ajax(settings); }, createOption: function ($el, id, name, selected, options) { var self = this, settings = {value: id, text: name}, selIds = [], sel = selected, idParam = self.idParam, pushId = function(str) { var s = $h.toStr(str); if (s) { selIds.push(s); } }; if (sel && (sel instanceof Array || sel instanceof Object)) { $.each(sel, function (key, val) { if (val instanceof Object) { pushId(val[idParam]); } else { pushId(val); } }); } else { pushId(sel); } $.extend(true, settings, (options || {})); if (selIds.length && $.inArray($h.toStr(id), selIds) > -1) { settings.selected = "selected"; } $("<option/>", settings).appendTo($el); }, renderSelect: function (data, placeholder, defVal, $select) { var self = this, idParam = self.idParam, nameParam = self.nameParam, options; $select.empty(); if (placeholder !== false) { self.createOption($select, "", placeholder, defVal); } if ($h.isEmpty(data)) { data = {}; } $.each(data, function (i, groups) { if (!$h.isEmpty(groups[idParam])) { options = groups[self.optionsParam] || {}; self.createOption($select, groups[idParam], groups[nameParam], defVal, options); } else { var $group = $('<optgroup>', {label: i}); $.each(groups, function (j, option) { options = option[self.optionsParam] || {}; self.createOption($group, option[idParam], option[nameParam], defVal, options); }); $group.appendTo($select); } }); }, getAjaxResults: function () { var self = this; return self.ajaxResults; } }; $.fn.depdrop = function (option) { var args = Array.apply(null, arguments), retvals = []; args.shift(); this.each(function () { var self = $(this), data = self.data('depdrop'), options = typeof option === 'object' && option, lang = options.language || self.data('language') || 'en', loc = {}, opts = {}; if (!data) { if (lang !== 'en' && !$h.isEmpty($.fn.depdropLocales[lang])) { loc = $.fn.depdropLocales[lang]; } $.extend(true, opts, $.fn.depdrop.defaults, $.fn.depdropLocales.en, loc, options, self.data()); data = new DepDrop(this, opts); self.data('depdrop', data); } if (typeof option === 'string') { retvals.push(data[option].apply(data, args)); } }); switch (retvals.length) { case 0: return this; case 1: return retvals[0]; default: return retvals; } }; $.fn.depdrop.defaults = { language: 'en', depends: '', initDepends: '', url: '', params: {}, ajaxSettings: {}, ajaxResults: {}, initialize: false, skipDep: false, loading: true, loadingClass: 'kv-loading', idParam: 'id', nameParam: 'name', optionsParam: 'options', parentParam: 'depdrop_parents', otherParam: 'depdrop_params', allParam: 'depdrop_all_params' }; $.fn.depdropLocales.en = { loadingText: 'Loading ...', placeholder: 'Select ...', emptyMsg: 'No data found' }; $.fn.depdrop.Constructor = DepDrop; /** * Convert automatically select with class 'depdrop' into dependent dropdowns. */ $(function () { $('select.depdrop').depdrop(); }); }));