rails 省市区 三级联动

routes.eb

get 'areas/tree'

Area表的数据

  { id: 1,  parent_id: nil, position: 1, name: "广东省", area_type: "District"},
  { id: 2,  parent_id: 1,   position: 1  , name: "广州市", area_type: "City"    },
  { id: 3,  parent_id: 1,   position: 2  , name: "韶关市", area_type: "City"    },
  { id: 4,  parent_id: 1,   position: 3  , name: "深圳市", area_type: "City"    },
  ...
  { id: 23,  parent_id: 2  , position: 1,  name: "荔湾区", area_type: "District"},
  { id: 24,  parent_id: 2  , position: 2,  name: "越秀区", area_type: "District"},
  { id: 25,  parent_id: 2  , position: 3,  name: "海珠区", area_type: "District"},
  ....

app/controllers/areas_controller.rb

 class AreasController < ApplicationController
    def tree
        all_areas = Area.all.map do |area|
       area.attributes.symbolize_keys
     end

     parent_id = nil

     areas = get_children(all_areas, parent_id)

        render json: {
       code: 0,
       data: areas,
     }
    end

    private

    def get_children(areas, parent_id)
        children = areas.
       select { |area| area[:parent_id] == parent_id }.
       sort_by! { |area| area[:position] }

     return nil if children.empty?

     children = children.map do |child|
       grandchildren = get_children(areas, child[:id])

       child = {
         id: child[:id],
         name: child[:name],
       }
       child[:children] = grandchildren unless grandchildren.nil?
       child
     end
     children
    end
 end

app/models/area.rb

 class Area < ActiveRecord::Base
    belongs_to :parent, class_name: 'Area'

    def ancestor_areas
      return @ancestor_areas if @ancestor_areas

      @ancestor_areas = []
      area = parent
      while area
        @ancestor_areas << area
        area = area.parent
      end
      @ancestor_areas
    end
 end

app/models/customer.rb


   # 直接产品分类及其祖先分类
   # 按分类的 level 由低到高排列
   def areas
     # if area
     #   ar = area.id
     #   @areas = []
     #   while ar
     #     @areas << Area.find(ar)
     #     ar = Area.find(ar).parent_id
     #   end
     # end
     # @areas.reverse unless @areas.blank?
     if area
       area.ancestor_areas.reverse << area
     else
       []
     end
   end

app/views/customers/_form.html.erb

<div class="form-group customer_select" data-api="<%= areas_tree_path%>" >
<%= f.hidden_field :area_id, autocomplete: 'off' %>
<% 
  areas =  @customer.areas.to_a 
  areas.fill(nil, areas.size...5)
%>
<% areas.each do |area|%>
<div class="form-group <%= 'hide' unless area %>" style="width:200px;top:3px;position:relative;">
  <select class="form-control" <%== %Q{data-selected="#{area.id}"} if area %>>
    <% if area %>
      <option value="<%= area.id %>"><%= area.name %></option>
    <% else %>
      <option value="">请选择</option>
    <% end %>
  </select>
</div>
<% end %>
</div>

area.js

<script>
   (function(){
     var container = $('.customer_select');

     // 禁止修改分类
     if (container.attr('data-disabled')) {
       container.find('select').prop('disabled', true);
       return;
     }

     var input = container.find('input')[0];
     container.find('select').prop('disabled', false);

     // 转为 id => [{id: 1, name: ''}],便于使用
     var idToChildren = {};
     var setChildren = function(areas){
       var i$, len$, customer;
       for (i$ = 0, len$ = areas.length; i$ < len$; ++i$) {
         customer = areas[i$];
         if (customer.children && customer.children.length) {
           idToChildren[customer.id] = customer.children;
           setChildren(customer.children);
         }
       }
     };

     // 初始化
     var initializeSelector = function(areas){
       setChildren(areas);

       // 重置,避免页面刷新后与选择器状态不一致
       input.value = container.find('select[data-selected]:last').val();

       updateOptions(container.find('select:first'), areas);
     };

     // 下一级分类的 select
     var nextSelect = function(select){
       return $(select).closest('.form-group').next('.form-group').find('select');
     };

     // 隐藏后面的选择框
     var hideFollowingSelect = function(select){
       $(select).closest('.form-group').nextAll('.form-group').addClass('hide').find('select').prop('disabled', true);
     };

     // 更新选项
     var updateOptions = function(select, areas){
       select.closest('.form-group').removeClass('hide');
       select.prop('disabled', false);

       var html = '<option value="">请选择</option>';
       var i, len, customer;
       for (i = 0, len = areas.length; i < len; ++i){
         customer = areas[i];
         html += '<option value="' + customer.id + '">' + customer.name + '</option>';
       }

       select.html(html);

       var id = select.attr('data-selected');
       if (id) {
         select.val(id);
         select.trigger('change');
         select.removeAttr('data-selected');
       }
       else {
         select.val('');
         hideFollowingSelect(select);
       }
     };

     // 选项改变时,保存选中 id,并更新后代选项
     container.on('change', 'select', function(){
       var id = this.value;

       // 保存选中值
       if (id) {
         input.value = id;
       }

       // 选中且有子分类时,更新后代节点
       if (id && idToChildren[id]) {
         updateOptions(nextSelect(this), idToChildren[id]);
       }
       // 否则隐藏后代节点
       else {
         hideFollowingSelect(this);
       }
     });

     // 获取分类数据,初始化
     $.get(container.attr('data-api'), null, function(data){
       if (data && data.code === 0) {
         initializeSelector(data.data);
       }
       else {
         flashPrompt('获取产品分类信息失败');
       }
     });
   })();
 </script>

app/views/customers/show.html.erb

<% areas =  @customer.areas[0..-1].to_a %>
<% areas.each do |area|%>
  <div class="form-group" style="width:200px;top:3px;position:relative;">
    <input type="text" class="form-control" disabled="" value="<%= area.name %>">
  </div>
<% end %>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值