Ajax级联选择框:以中国的省市地区三级联动选择为例

lzqustc 2009-02-04

首先:确定数据库的设计,下面将省市地区数据以如下方式存入数据库的cities表:
+--------+--------------+
| id     | cname       |
+--------+--------------+
| 110000 | 北京市       |         第1级
| 110100 | 北京市       |         第2级
| 110101 | 东城区       |         第3级
| 110102 | 西城区       |         第3级
+--------+--------------+

那么,要取所有省(直辖市)的数据,可通过下面语句:
mysql> select * from cities where (id mod 10000 = 0 );

取某个省(直辖市)的所有市的数据,可通过下面语句:
mysql> select * from cities where (id mod 100 = 0 ) and (id div 10000 = #{province_id} div 10000 )      
      and (id != #{province_id});

取第三级数据:
mysql>  select * from cities where(id div 100 = #{city_id} div 100 )  and  (id != #{city_id});


下面开始写rails 应用:步骤如下
①、ruby script/generate scaffold  city  cname:string

②、写取所有省(直辖市)的数据的函数
class City < ActiveRecord::Base   
      
  def self.get_province_select_options  
     City.find_by_sql("select * from cities where (id mod 10000 =0 )").collect { |row|  [row.cname,row.id] }.insert(0,["--请选择--",0])
  end
end

③、假设这个省市地区级联应用是出现在公司(Company)的视图上,而且companies表里有相应的字段province_id、city_id、area_id。
首先在./views/layouts/companies.html.erb
添加<%= javascript_include_tag 'prototype' %> 以便定义Ajax请求,

接着就可以修改视图了Company的new/eidt视图如下:
%table
   %tr
      %td
         =f.select(:province_id, City.get_province_select_options,{},
            "onchange" => remote_function(
                :with => " 'province_id = '+ value + '&partial = select_city' ",
                :update =>"cityid", :complete => "Element.hide('areaid') ",
                :url =>{:controller => :cities, :action => :index_city}  ),
           :style=>"width:150px")
      %td
        %div{:id=>'cityid'}
      %td          
        %div{:id=>'areaid'}   
注意:对于haml模板,上面的分行是会出错的,f.select()最好写成一行。


接着就要相应修改:controller、:action、:partial
④、修改CitiesController,主要是定义 action ——index_city

class CitiesController < ApplicationController

   def index_city  
     if params[:province_id]
       province_id  = params[:province_id]
       @cities = City.find_by_sql("select * from cities where (id mod 100 =0 )and (id div 10000 = #{province_id} div 10000 ) 

      and (id != #{province_id})").collect {|c| [c.cname, c.id]}.insert(0,["--请选择--",0])             
     else
       @cities = City.find(:all).collect {|c| [c.cname, c.id]}   
     end
     respond_to do |format|     
       format.html { render :partial => params[:partial]}     
       format.xml { render: xml => @cities.to_xml }  
     end
   end     
end

⑤、写partial—— select_city, 在./views/cities新建一个

_select_city.html.erb,内容如下:
<%= select(:company, :city_id, @cities,{},
  "onchange" => remote_function( :with => "'city_id='+value+ '&partial = select_area' ",
       :update => "areaid",:complete => "Element.show('areaid')",
       :url =>{:controller => :cities,:action => :index_area} ),
        :style=>"width:160px")
%>

同理,要写一个action —— index_area,和一个partial ——select_area
class CitiesController < ApplicationController

   def index_area  
     if params[:city_id]
       city_id  = params[:city_id]
       @areas = City.find_by_sql("select * from cities where (id mod 100 =0 )
               and (id div 10000 = #{city_id } div 10000 )  and
               (id != #{city_id })").collect {|c| [c.cname, c.id]}.insert(0,["--请选择--",0])             
     else
       @areas = City.find(:all).collect {|c| [c.cname, c.id]}   
     end
     respond_to do |format|     
       format.html { render :partial => params[:partial]}     
       format.xml { render: xml => @areas.to_xml }  
     end
   end     
end

在./views/cities新建一个_select_area.html.erb,内容如下:
<%= select(:company, :area_id, @areas,{},:style=>"width:150px")%>

 

 

OK, 在Compnay的视图中使用这个三级联动菜单,已经没问题了。

 

来自: http://lzqustc.iteye.com/

Global site tag (gtag.js) - Google Analytics