160 lines
6.0 KiB
JavaScript
160 lines
6.0 KiB
JavaScript
|
/*
|
||
|
* Chained - jQuery / Zepto chained selects plugin
|
||
|
*
|
||
|
* Copyright (c) 2010-2017 Mika Tuupola
|
||
|
*
|
||
|
* Licensed under the MIT license:
|
||
|
* http://www.opensource.org/licenses/mit-license.php
|
||
|
*
|
||
|
* Project home:
|
||
|
* http://www.appelsiini.net/projects/chained
|
||
|
*
|
||
|
* Version: 2.0.0-beta.3
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
;(function($, window, document, undefined) {
|
||
|
"use strict";
|
||
|
|
||
|
$.fn.remoteChained = function(options) {
|
||
|
|
||
|
var settings = $.extend({}, $.fn.remoteChained.defaults, options);
|
||
|
|
||
|
/* Loading text always clears the select. */
|
||
|
if (settings.loading) {
|
||
|
settings.clear = true;
|
||
|
}
|
||
|
|
||
|
return this.each(function() {
|
||
|
|
||
|
/* Save this to self because this changes when scope changes. */
|
||
|
var self = this;
|
||
|
var request = false; /* Track xhr requests. */
|
||
|
|
||
|
$(settings.parents).each(function() {
|
||
|
$(this).bind("change", function() {
|
||
|
|
||
|
/* Build data array from parents values. */
|
||
|
var data = {};
|
||
|
$(settings.parents).each(function() {
|
||
|
var id = $(this).attr(settings.attribute);
|
||
|
var value = ($(this).is("select") ? $(":selected", this) : $(this)).val();
|
||
|
data[id] = value;
|
||
|
|
||
|
/* Optionally also depend on values from these inputs. */
|
||
|
if (settings.depends) {
|
||
|
$(settings.depends).each(function() {
|
||
|
/* Do not include own value. */
|
||
|
if (self !== this) {
|
||
|
var id = $(this).attr(settings.attribute);
|
||
|
var value = $(this).val();
|
||
|
data[id] = value;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/* If previous request running, abort it. */
|
||
|
/* TODO: Probably should use Sinon to test this. */
|
||
|
if (request && $.isFunction(request.abort)) {
|
||
|
request.abort();
|
||
|
request = false;
|
||
|
}
|
||
|
|
||
|
if (settings.clear) {
|
||
|
if (settings.loading) {
|
||
|
/* Clear the select and show loading text. */
|
||
|
build.call(self, {"" : settings.loading});
|
||
|
} else {
|
||
|
/* Clear the select. */
|
||
|
$("option", self).remove();
|
||
|
}
|
||
|
|
||
|
/* Force updating the children to clear too. */
|
||
|
$(self).trigger("change");
|
||
|
}
|
||
|
|
||
|
request = $.getJSON(settings.url, data, function(json) {
|
||
|
json = settings.data(json);
|
||
|
build.call(self, json);
|
||
|
/* Force updating the children. */
|
||
|
$(self).trigger("change");
|
||
|
});
|
||
|
});
|
||
|
|
||
|
/* If we have bootstrapped data given in options. */
|
||
|
if (settings.bootstrap) {
|
||
|
build.call(self, settings.bootstrap);
|
||
|
settings.bootstrap = null;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/* Build the select from given data. */
|
||
|
function build(json) {
|
||
|
/* If select already had something selected, preserve it. */
|
||
|
var selectedKey = $(":selected", self).val();
|
||
|
|
||
|
/* Clear the select. */
|
||
|
$("option", self).remove();
|
||
|
|
||
|
if ($.isArray(json)) {
|
||
|
/* Add new options from json which is an array of objects. */
|
||
|
/* [ {"":"--"},{"series-1":"1 series"},{"series-3"}:{"3 series"}] */
|
||
|
$.each(json, function(key, value) {
|
||
|
$.each(value, function(key, value) {
|
||
|
if ("selected" === key) {
|
||
|
selectedKey = value;
|
||
|
} else {
|
||
|
var option = $("<option />").val(key).append(value);
|
||
|
$(self).append(option);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
} else {
|
||
|
/* Add new options from json which is an object. */
|
||
|
/* {"":"--","series-1":"1 series","series-3":"3 series"} */
|
||
|
$.each(json, function(key, value) {
|
||
|
if (json.hasOwnProperty(key)) {
|
||
|
/* Set the selected option from JSON. */
|
||
|
if ("selected" === key) {
|
||
|
selectedKey = value;
|
||
|
} else {
|
||
|
var option = $("<option />").val(key).append(value);
|
||
|
$(self).append(option);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/* Loop option again to set selected. IE needed this... */
|
||
|
$(self).children().each(function() {
|
||
|
if ($(this).val() === selectedKey + "") {
|
||
|
$(this).attr("selected", "selected");
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/* If we have only the default value disable select. */
|
||
|
if (1 === $("option", self).length && $(self).val() === "") {
|
||
|
$(self).prop("disabled", true);
|
||
|
} else {
|
||
|
$(self).prop("disabled", false);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/* Alias for those who like to use more English like syntax. */
|
||
|
$.fn.remoteChainedTo = $.fn.remoteChained;
|
||
|
|
||
|
/* Default settings for plugin. */
|
||
|
$.fn.remoteChained.defaults = {
|
||
|
attribute: "name",
|
||
|
depends: null,
|
||
|
bootstrap: null,
|
||
|
loading: null,
|
||
|
clear: false,
|
||
|
data: function(json) { return json; }
|
||
|
};
|
||
|
|
||
|
})(window.jQuery || window.Zepto, window, document);
|