Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Populate a drop down using result from a previous drop down [duplicate]

I have a Rails database with Schools and Majors in it. Once the user selects his school, I want to fill up the major's drop down with only the majors from the corresponding school. Currently I have two working drop downs, but as you can see they just select all values. Will I need Json/Ajax/JavaScript for this, and if so how can I go about implementing it?

<div class="field">
  <%= f.label :school_id %><br>
  <%= f.collection_select :school_id, School.order(:name),:id,:name, include_blank: false %>
</div>
<div class="field">
  <%= f.label :major_id %><br>
  <%= f.collection_select :major_id, Major.order(:name),:id,:name, include_blank: false %>
</div>
like image 380
James L. Avatar asked Apr 19 '15 01:04

James L.


People also ask

How do I create a drop-down list in Excel from a previous selection?

In the same or in another spreadsheet, select a cell or several cells in which you want your primary drop-down list to appear. Go to the Data tab, click Data Validation and set up a drop-down list based on a named range in the usual way by selecting List under Allow and entering the range name in the Source box.


1 Answers

Edit

The current solution is using an async request on each dropdown selection. Assuming you have a small total corpus of choices (let's say <5k), it may be better to only have 1 async operation when the page loads, and then use JS to populate the dropdowns as the user makes their choices. This would save a lot of network calls, and provide a better user experience.

Original

Alright, so after much searching I've arrived at a working AJAX request (which I will post here for posterity).

When creating a new course in my database there is a Schools and a Major foreign key that must be non-null. Here are the dropdowns

<!-- app/views/courses/_form.html.erb -->
<div class="field">
  <%= f.label :school_id %><br>
  <%= f.collection_select :school_id, School.order(:name),:id,:name, {include_blank: false},{:id=>'school_id_select'} %>
</div>
<div class="field">
  <%= f.label :major_id %><br>
  <%= f.collection_select :major_id, [],:id,:name, {include_blank: false},{:id=>'major_id_select'} %>
</div>

Now that the HTML is up, we need some JavaScript (and jQuery) to process the AJAX request

//app/assests/javascripts/courses.js (note this was generated as a .coffee file, which I changed to .js as I don't know CoffeeScript
console.log('loaded courses.js')//check that the file is loaded

$(document).on('change','#school_id_select', function () {//change majors when user changes school
   load_majors_from_school_dropdown();
});

$(document).ready(load_majors_from_school_dropdown);//populate majors when page loads with first school

function load_majors_from_school_dropdown(){
    var request = "/majors/find_majors_given_school_id?school_id=" //access controller of interest
        + $('#school_id_select').val();

    var aj = $.ajax({
        url: request,
        type: 'get',
        data: $(this).serialize()
    }).done(function (data) {
         change_majors(data);//modify the majors' dropdown
    }).fail(function (data) {
         console.log('AJAX request has FAILED');
    });
};

//modify the majors' dropdown
function change_majors(data) { 
    $("#major_id_select").empty();//remove all previous majors
    for(i = 0;i<data.length;i++){ 
        $("#major_id_select").append(//add in an option for each major
            $("<option></option>").attr("value", data[i].id).text(data[i].name)
        );
    }
};

Take note of the 'request' variable. This indicates the controller & action that will process the request. Now we must make it. My Major controller already existed, so we only have to add the action. First add the action's route to make the Rails server aware of the action.

#config/routes.rb
Rails.application.routes.draw do
  #...
  get 'majors/find_majors_given_school_id'
  #...
end

Now create the action in the Major controller

#app/controllers/majors_controller.rb
#custom action for AJAX/JSON calls. Note this can be done multiple ways
def find_majors_given_school_id
   school_id = params[:school_id]#utilizes the url to extract school_id ".../find_majors_given_school_id?school_id=123123"
   puts "THIS IS MY SCHOOL ID :: #{school_id}"#view this in teminal
    
   majors = Major.search_for_school_id(school_id).as_json#query the model for the data and convert it to a hash using as_json
   puts "THESE ARE MY MAJORS IN A HASH :: #{majors}"
   respond_to do |format|
        format.json { 
            render json: majors
        } 
   end
end

Finally, we have to create the query to extract this information in our model.

#app/models/major.rb
class Major < ActiveRecord::Base
    has_many :courses, dependent: :destroy
    belongs_to :school, :foreign_key => "school_id"

    def self.search_for_school_id(id)
        where("school_id = ?",id)        
    end
    #...
end

I think that's everything. There are certainly other ways of implementing this, but this one worked for me. Good luck!

like image 172
James L. Avatar answered Oct 24 '22 23:10

James L.