PageRenderTime 29ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Detergent/jquery.detergent-1.0.js

http://detergent.codeplex.com
JavaScript | 238 lines | 188 code | 14 blank | 36 comment | 25 complexity | 1683f744243e1cd39b4e0dfdea671876 MD5 | raw file
  1. /*
  2. * Detergent CascadingDropDown : a jQuery plugin, version: 1.0 (2012-02-10)
  3. * @requires jQuery v1.7.1 or later
  4. * By Ross Dickinson: http://www.rossisdead.com
  5. * Based off the CascadingDropDown plugin by Raj Kaimal: https://github.com/rajkaimal/CascadingDropDown
  6. * Licensed under the MIT: http://www.opensource.org/licenses/mit-license.php
  7. *
  8. * Detergent is a jQuery plugin that can be attached to a select list to get automatic population.
  9. * Each time the source element changes value, an ajax request is made to retrieve a list of values for
  10. * the select list. The respose from the ajax request should be in json with the following format
  11. *
  12. * [{
  13. * "text": "John",
  14. * "value": "10326"
  15. * },
  16. * {
  17. * "text": "Jane",
  18. * "value": "10801"
  19. * }]
  20. */
  21. // TODO: Finish the destroy method. Needed on both normal and unobtrusive.
  22. // TODO: Figure out how this is gonna work with being initialized from ajax content.
  23. // Don't wanna have the same annoyance that the unobtrusive validation library has.
  24. (function($) {
  25. var detergent = function(options) {
  26. if (typeof options.parentSelector === undefined) {
  27. throw 'A parent selector is required';
  28. }
  29. if (typeof options.actionPath === undefined) {
  30. throw 'An action path is requried';
  31. }
  32. options = $.extend({}, methods.defaults, options);
  33. return this.each(function() { methods.initialize($(this), options); });
  34. };
  35. var methods = {
  36. 'defaults': {
  37. // Values that must be set
  38. 'actionPath': null,
  39. 'parentSelector': null,
  40. // Optional
  41. 'async': true,
  42. 'promptText': '-- Select --',
  43. 'loadingText': 'Loading ..',
  44. 'errorText': 'Error loading data.',
  45. 'unselectedText': '-- Select --',
  46. 'postData': null,
  47. 'onLoading': null,
  48. 'onLoaded': null,
  49. 'httpMethod': 'GET'
  50. },
  51. 'addOption': function($select, value, text) {
  52. $select.append(methods.createOption(value, text));
  53. },
  54. 'clear': function($select) {
  55. $select.empty();
  56. },
  57. 'createOption': function(value, text) {
  58. value = value || '';
  59. return $('<option></option>')
  60. .attr('value', value)
  61. .text(text || value);
  62. },
  63. 'destroy': function($select) {
  64. var options = methods.getOptions($select);
  65. $(options.parentSelector).unbind('.detergent');
  66. $select.removeData('options', null);
  67. $select.removeData('data-cascading-initialized');
  68. },
  69. 'disable': function($select) {
  70. methods.clear($select);
  71. $select.attr('disabled', 'disabled');
  72. methods.addOption($select, '', methods.getOptions($select).promptText);
  73. $select.trigger('change');
  74. },
  75. 'enable': function($select) {
  76. $select.removeAttr('disabled');
  77. $select.trigger('change');
  78. },
  79. 'getOptions': function($select) {
  80. return $select.data('options');
  81. },
  82. 'initialize': function($select, options) {
  83. var initialized = !(!$select.data('data-cascading-initialized'));
  84. if (!initialized) {
  85. methods.setOptions($select, options);
  86. if ($select.children().size() === 0) {
  87. methods.disable($select);
  88. }
  89. $(options.parentSelector).bind('change.detergent', function() {
  90. if ($(options.parentSelector).val()) {
  91. methods.post($select);
  92. }
  93. else {
  94. methods.disable($select);
  95. }
  96. });
  97. $select.data('data-cascading-initialized', true);
  98. }
  99. else {
  100. if (options === 'destroy') {
  101. methods.destroy($select);
  102. }
  103. }
  104. },
  105. 'onLoaded': function($select) {
  106. methods.enable($select);
  107. var onload = methods.getOptions($select).onLoaded;
  108. $.isFunction(onload) && onload.call($select);
  109. },
  110. 'onLoading': function($select) {
  111. methods.clear($select);
  112. var opts = methods.getOptions($select);
  113. methods.addOption($select, '', opts.loadingText);
  114. $.isFunction(opts.onLoading) && opts.onLoading.call($select);
  115. },
  116. 'onAjaxSuccess': function($select, data) {
  117. var $data = $(data);
  118. if ($data.length === 0) {
  119. methods.disable($select);
  120. }
  121. else {
  122. methods.reset($select);
  123. $data.each(function() {
  124. methods.addOption($select, this.value || this.Value, this.text || this.Text);
  125. });
  126. methods.onLoaded($select);
  127. }
  128. },
  129. 'post': function($select) {
  130. methods.onLoading($select);
  131. var opts = methods.getOptions($select);
  132. $.ajax({
  133. 'async': opts.async,
  134. 'data': ((typeof opts.postData == 'function') ? opts.postData() : opts.postData) || $(opts.parentSelector).serialize(),
  135. 'dataType': 'json',
  136. 'error': function() {
  137. methods.showError($select);
  138. },
  139. 'success': function(data) {
  140. return methods.onAjaxSuccess($select, data);
  141. },
  142. 'type': opts.httpMethod,
  143. 'url': opts.actionPath
  144. });
  145. },
  146. 'reset': function($select) {
  147. methods.clear($select);
  148. $select.trigger('change');
  149. },
  150. 'setOptions': function($select, value) {
  151. return $select.data('options', value);
  152. },
  153. 'showError': function($select) {
  154. methods.clear($select);
  155. methods.addOption($select, '', methods.getOptions($select).errorText);
  156. }
  157. };
  158. // This makes our methods easily replacable.
  159. $.extend(detergent, methods);
  160. // And finally, make it accessible to jQuery
  161. $.fn.detergent = detergent;
  162. })(jQuery);
  163. (function($) {
  164. var unobtrusiveDetergent = function(options) {
  165. this.each(function() {
  166. methods.initialize($(this), options);
  167. });
  168. };
  169. var methods = {
  170. 'initialize': function($dropDown, options) {
  171. // This makes it easier for us to pass in any group of
  172. // select elements without having to include the data-cascading
  173. // attribute check outside of this method.
  174. if ($dropDown.attr('data-cascading') !== 'true') {
  175. // No attribute = no init.
  176. return;
  177. }
  178. // meaning someone just called $('something').unobtrusiveDetergent();
  179. if (!options) {
  180. var data = methods.getSettings($dropDown);
  181. // Pass in the data object since it'll count as the various text options
  182. $dropDown.detergent(data);
  183. }
  184. else {
  185. // The only option to pass at the moment is 'destroy'.
  186. methods.destroy($dropDown);
  187. }
  188. },
  189. 'destroy': function($dropDown) {
  190. $dropDown.detergent('destroy');
  191. },
  192. 'getSettings': function($dropDown) {
  193. var data = $dropDown.data('cascadingData');
  194. if (data == null) {
  195. data = {
  196. 'actionPath': $dropDown.attr('data-cascading-action'),
  197. 'parentSelector': $dropDown.attr('data-cascading-dependson'),
  198. 'errorText': $dropDown.attr('data-cascading-errortext'),
  199. 'httpMethod': $dropDown.attr('data-cascading-httpmethod'),
  200. 'loadingText': $dropDown.attr('data-cascading-loadingtext'),
  201. 'promptText': $dropDown.attr('data-cascading-prompttext'),
  202. 'async': methods.getAsync($dropDown)
  203. };
  204. $dropDown.data('cascadingData', data);
  205. }
  206. return data;
  207. },
  208. 'getAsync': function($dropDown) {
  209. var val = $dropDown.attr('data-cascading-async');
  210. if (val === undefined) {
  211. // It's a string, and if it's not set, we're defaulting to true.
  212. return true;
  213. }
  214. else {
  215. return (val === 'true');
  216. }
  217. }
  218. };
  219. $.fn.unobtrusiveDetergent = unobtrusiveDetergent;
  220. })(jQuery);
  221. $(document).ready(function() {
  222. $('select').unobtrusiveDetergent();
  223. });