DevInterface: Comunicato Stampa
  • 12 dic DevInterface
    14:03 - 12 dic 2013 Veneto http://feedproxy.google.com/~r/devinterfaceblog/it/~3/grSYiRtaPpE/

    Come implementare in Rails 4 delle dropdown dipendenti con script jQuery non intrusivo

    Di recente ho dovuto implementare in una view la classica ricerca con due select dipendenti l’una dall’altra. Volevo però lasciare il template .erb il più possibile pulito e rendere il codice che carica le option della select figlia il più possibile riutilizzabile e generico.

    Supponiamo dunque di avere due modelli, SpecializationType e Specialization, così composti:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class SpecializationType < ActiveRecord::Base
      # FIELDS
      # RELATIONS
      has_many :specializations
      # TRIGGERS
      # VALIDATIONS
      validates :name, :presence => true
      validates :description, :presence => true
      # SCOPES
      # OTHER
      def to_s
        name
      end
    end


    class Specialization < ActiveRecord::Base
      # FIELDS
      # RELATIONS
      belongs_to :specialization_type
      has_and_belongs_to_many :users
      # TRIGGERS
      # VALIDATIONS
      validates :name, :presence => true
      validates :description, :presence => true
      validates :specialization_type, :presence => true
      # SCOPES
      # OTHER
      def to_s
        name
      end
    end

    Come si puo’ notare, Specialization dipende dalla SpecializationType che andremo a selezionare.

    Nel nostro template, creeremo le due dropdown in questo modo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <%= form_tag users_path, {:method => :get, :class => "users_search_form"} do %>
          <%= select_tag :specialization_type_id, options_from_collection_for_select(SpecializationType.all, "id", "name"), :prompt => "Select a specialization type" %>
          <%= select_tag :specialization_id, options_from_collection_for_select([], "id", "name"),
                         "data-option-dependent" => true,
                         "data-option-observed" => "specialization_type_id",
                         "data-option-url" => "/specialization_types/:specialization_type_id:/specializations.json",
                         "data-option-key-method" => :id,
                         "data-option-value-method" => :name %>
          <br/>
          <%= submit_tag "Cerca" %>
      <% end %>

    Come si puo’ notare, la dropdown figlia indica in una serie di “data-option” tutto il necessario per poter caricarsi a runtime gli elementi.
    In particolare:

    “data-option-dependent” => true, indica che questa dropdown dipende da una dropdown padre
    “data-option-observed” => “specialization_type_id”, specifica l’id della dropdown da monitorare. Il suo cambio di valore scatenerà la richiesta al server
    “data-option-url” => “/specialization_type/:specialization_type_id:/specializations.json”, è l’url che andrò a chiamare sul server. Lo script andrà a sostituire :specialization_type_id: con l’id dell’elemento selezionato nella dropdown padre
    “data-option-key-method” => :id, indica che userò il campo ID del json tornato dal server come attrbuto “chiave” della < option >
    “data-option-value-method” => :name, indica che userò il campo NAME del json tornato dal server come attrbuto “valore” della < option >

    Aggiungiamo poi in application.js il seguente codice per gestire tutte le dropdown dipendenti:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
        jQuery(document).ready(function () {
            $('select[data-option-dependent=true]').each(function (i) {
                var observer_dom_id = $(this).attr('id');
                var observed_dom_id = $(this).data('option-observed');
                var url_mask = $(this).data('option-url');
                var key_method = $(this).data('option-key-method');
                var value_method = $(this).data('option-value-method');
                var prompt = $(this).has('option[value=]').size() ? $(this).find('option[value=]') : $('<option value=\"\">').text('Select a specialization');
                var regexp = /:[0-9a-zA-Z_]+:/g;
                var observer = $('select#' + observer_dom_id);
                var observed = $('#' + observed_dom_id);

                if (!observer.val() && observed.size() > 1) {
                    observer.attr('disabled', true);
                }
                observed.on('change', function () {
                    observer.empty().append(prompt);
                    if (observed.val()) {
                        url = url_mask.replace(regexp, observed.val());
                        $.getJSON(url, function (data) {
                            $.each(data, function (i, object) {
                                observer.append($('<option>').attr('value', object[key_method]).text(object[value_method]));
                                observer.attr('disabled', false);
                            });
                        });
                    }
                });
            });
        });

    Basterà ora definire nel file routes.rb la seguente rotta:

    1
    get "specialization_types/:specialization_type_id/specializations" => "application#specializations", :as => "specializations", :format => :json

    Ed infine implementare il metodo nel controller:

    1
    2
    3
    4
    5
    6
    def specializations
      specialization_type = SpecializationType.find(params[:specialization_type_id])
      respond_to do |format|
        format.json { render :json => specialization_type.specializations }
      end
    end

Coobiz.it - 2024
Social Network | Trova aziende