这标题起得好长好牛B,喔呵呵呵呵……
忙活一下午,写出这么个玩意,其中emptySelect和loadSelect方法的代码来自《jQuery in Action》一书,稍有改动。childSelect是自己照着加的,可能写得不太好看。
(function($){$.fn.loadSelect = function(optionsDataArray){
return this.each(function(){
if(this.tagName == 'SELECT'){
var selectElement = this;
$.each(optionsDataArray, function(index, optionData){
selectElement.options.add(new Option(optionData.text, optionData.value));
});
var defaultOption = new Option('\u8bf7\u9009\u62e9', '');
defaultOption.selected = true;
selectElement.options.add(defaultOption);
}
});
};
$.fn.childSelect = function(selector, makeURL){
var elem = this[0];
if(selector === undefined){
return elem.child ? this.pushStack(elem.child) : undefined;
}
elem.child = $(selector)[0];
this.change(function(event){
var childSelect = $(this).childSelect();
childSelect.emptySelect();
if($(this).val()){
childSelect.attr('disabled', false);
$.getJSON(makeURL.apply($(this)), function(data){
childSelect.loadSelect(data).change();
});
}else{
childSelect.attr('disabled', true);
}
if(childSelect.childSelect()) childSelect.change();
});
return this.pushStack(elem.child);
};
$.fn.emptySelect = function(){
return this.each(function(){
if(this.tagName == 'SELECT')
this.options.length = 0;
});
};})(jQuery);
这里解释一下childSelect的用法:
这个方法是用来给一个select元素设置子级select元素的,一旦设置了子级select元素,父select元素的change事件触发时将通过$.getJSON向服务器发送一个请求,并将返回的json填充到子级select元素中。如果想让父select元素的某一项选中时不发送请求,只要将这一项的value设置成空字符串''即可:如
<select><option value=''>请选择</option></select>
参数selector用来选择子select元素,跟$(selector)的用法一样。
makeURL必须是一个方法,这个方法用于创建要请求的url,上下文(即this)为父select元素的包装集对象(即jQuery包装后的父select元素)。
这个方法类似于val()方法——省略参数的时候是用于获取子select元素的包装集。
这个版本的代码对服务端返回的JSON的格式有一些要求,返回的JSON数组必须是这种格式:
[{text:'一年1班', value:'1'},{text:'一年2班', value:'2'}]
使用方法如下:
$('#grade').childSelect('#class', function(){return 'grades/'+this.val()+'/classes'}).end().change()
也可以链式地继续往后面添加子select元素的子select元素,或者直接给子select元素添加事件。
接着我遇到了一些问题。rails的to_json生成的json格式一般是这样的
[{class_name1:{attr1.1:value1.1,attr1.2:value1.2}},{class_name2:{attr2.1:value2.1,attr2.2:value2.2}}]
,没什么规律的,或者说规律比较复杂,要给select元素填充不同的ruby类数组的话,就必须知道这个ruby类的类名、用来做text和value的属性名。
我修改了一下loadSelect和childSelect方法,如下:
(function($){$.fn.loadSelect = function(optionsDataArray, hash){
return this.each(function(){
if(this.tagName == 'SELECT'){
var selectElement = this;
$.each(optionsDataArray, function(index, optionData){
selectElement.options.add(new Option(optionData[hash.className][hash.text], optionData[hash.className][hash.value]));
var defaultOption = new Option('\u8bf7\u9009\u62e9', '');
defaultOption.selected = true;
selectElement.options.add(defaultOption);
});
}
});
};
$.fn.childSelect = function(selector, makeURL, hash){
var elem = this[0];
if(selector === undefined){
return elem.child ? this.pushStack(elem.child) : undefined;
}
elem.child = $(selector)[0];
this.change(function(event){
var childSelect = $(this).childSelect();
childSelect.emptySelect();
if($(this).val()){
childSelect.attr('disabled', false);
$.getJSON(makeURL.apply($(this)), function(data){
childSelect.loadSelect(data, hash).change();
});
}else{
childSelect.attr('disabled', true);
}
if(childSelect.childSelect()) childSelect.change();
});
return this.pushStack(elem.child);
};})(jQuery);
就是给方法添加了一个hash(或者说对象)作为参数,让客户端代码来指定ruby类的类名、用于text和value的属性名,使用的时候就是多传一个hash,像这样:
$('#grade').childSelect('#clazz', function(){return 'grades/'+this.val()+'/classes'}, {className:'clazz', value:'id', text:'class_no'}).end().change();
还有另外一种解决方法,就是给rails的每个对象添加一个json_for_select方法,生成这种格式的JSON:
[{text:'一年1班', value:'1'},{text:'一年2班', value:'2'}]
,这样就可以免去上面多出来的那个hash。
问题是……json_for_select该怎么写,我还没有头绪……似乎要同时去修改ActiveSuppor::JSON和Object。
===========================================================
改好了,在config/initializers下添加一个extension.rb,内容:
class Object
def json_for_select(hash)
json = to_json(:only => [hash[:text], hash[:value]])
json = json.gsub(Regexp.new("\"#{hash[:text]}\":"), "\"text\":").gsub(Regexp.new("\"#{hash[:value]}\":"), "\"value\":")
json = json.gsub(/\{"\w+":\s\{/, '{').gsub(/\}\}/, '}') if ActiveRecord::Base.include_root_in_json
json
end
end
解释:rails启动的时候会自动加载config/initializers下的文件并执行。ActiveRecord::Base.include_root_in_json如果为true,to_json生成的JSON带有类名,如果为false,则不带类名。最后把controller中的
format.html { render :json => @classes.to_json }
换成
format.html { render :json => @classes.json_for_select(:text =>'class_no', :value=>'id')
即可。
分享到:
相关推荐
在网页开发中,jQuery是一个非常流行的JavaScript库,它极大地简化了DOM操作、事件处理和Ajax交互。本主题将深入探讨如何使用jQuery实现动态绑定和二级联动效果,特别关注于DropDownList(下拉列表)的交互设计。这...
基于jQuery实现省市联动效果的知识点主要包括以下几点: 1. jQuery基础:首先,要实现省市联动效果,需要了解jQuery的使用方法。jQuery是一个快速、简洁的JavaScript库,它简化了HTML文档遍历、事件处理、动画和...
为了提高代码的可重用性和可维护性,我们可以将上述逻辑封装为一个插件。创建一个`jquery.areas.js`文件,定义如下插件: ```javascript (function($) { $.fn.extend({ areas: function(options) { var settings...
这个标题所指的"中国地区三级联动菜单"是一个专为选择中国地区设计的下拉菜单组件,通常包括省份、城市和区县三个级别的选择,用户可以逐级下拉选择,实现快速定位。 该菜单的设计和实现涉及到多个IT知识点: 1. *...
在这个经典例子中,我们看到它被应用于一个省、市、地区的选择菜单,通过AJAX实现三个下拉框的联动效果。下面我们将深入探讨这个技术及其在JAVA和JSP环境中的应用。 首先,我们要理解AJAX(Asynchronous JavaScript...
7. **封装组件**:为了提高代码复用性,可以将此功能封装成一个可重用的组件,方便在其他项目中应用。 【标签】"源码"和"工具"暗示这篇博客可能提供了实现省市联动的示例代码,并且可能还介绍了一些辅助开发的工具...
接下来,我们讨论封装的方式,将上述功能包装成一个可复用的插件。通过封装,我们可以减少代码重复,提高代码的可维护性和复用性。封装通常涉及创建一个自定义的jQuery插件函数,比如`$.fn.extend`,然后在需要的...