Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic select dropdown Rails 5 / AJAX

I'm trying to make a three input select menu that allows a user to filter down to one course in the database to select. So the user first selects the location, and based on that selection is given all the options of courses that are in that location. He can then press select and be brought to that course. The dynamic part has my mind bent a little. I'd love any help if possible. I understand some AJAX will probably be required but I'm lost on that end. Any advice please.

Code so far. View.

<div class="row no-gutters wow slideInUp" data-wow-duration="1s">
  <div class="col-md-12 home-form">
    <form class="form-inline">
      <select class="custom-select mb-0 mr-sm-0 mb-sm-0">
        <option selected>Location</option>
        <%= @locations.each do |location| %>
                <option value="<%= location.id %>"><%= location.header %></option>
        <% end %>
      </select>
      <select class="custom-select mb-0 mr-sm-0 mb-sm-0">
        <option selected>Course Type</option>
        <%= @courses.each do |course| %>
                <option value="<%= course.id %>"><%= course.course_type %></option>
        <% end %>
      </select>

      <select class="custom-select mb-0 mr-sm-0 mb-sm-0">
        <option selected>Course</option>
        <%= @courses.each do |course| %>
                <option value="<%= course.id %>"><%= course.title %></option>
        <% end %>
      </select>
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>
</div>

Controller just pulls in variable for all locations and courses.

Then models have associations as below.

course

belongs_to :location

location

has_many :courses, dependent: :destroy

I can see all the courses and locations from the dropdown but I need to be able to select a location and then only see courses that are in that location please. If any AJAX code is responded i'd love an explanation of what's happening in the code if you have time. Thanks a million.

enter image description here

like image 301
Bradley Avatar asked Jan 26 '18 14:01

Bradley


1 Answers

You can follow my instructions to add dynamic dependent drop down list to your rails applications -

Step -1. Add an action to route file for getting all courses for a specific location.

# config/routes.rb

Rails.application.routes.draw do

  get 'get_courses_by_location/:location_id', to: 'courses#get_courses_by_location'  
  get '/course_search' => 'courses#course_search'

 end

Step -2. Create courses controller with get_courses_by_location action

# app/controllers/courses_controller.rb

class CoursesController < ApplicationController

  def get_courses_by_location
    @courses = Course.where("location_id = ?", params[:location_id])
    respond_to do |format|
      format.json { render :json => @courses }
    end
  end 
  def course_search
    if params[:location].present? && params[:location].strip != ""
      @courses = Course.where("location_id = ?", params[:location])
    else
      @courses = Course.all
    end
  end

end

Step -3. Create a js file for populating the courses dropdown list with changes the location dropdown.

# app/assets/javascripts/courses.js

$(function() {

   if ($("select#location").val() == "") {
    $("select#course option").remove();
    var row = "<option value=\"" + "" + "\">" + "Course" + "</option>";
    $(row).appendTo("select#course");
   }
   $("select#location").change(function() {
    var id_value_string = $(this).val();
    if (id_value_string == "") {
     $("select#course option").remove();
     var row = "<option value=\"" + "" + "\">" + "Course" + "</option>";
     $(row).appendTo("select#course");
    } else {
     // Send the request and update course dropdown
     $.ajax({
      dataType: "json",
      cache: false,
      url: '/get_courses_by_location/' + id_value_string,
      timeout: 5000,
      error: function(XMLHttpRequest, errorTextStatus, error) {
       alert("Failed to submit : " + errorTextStatus + " ;" + error);
      },
      success: function(data) {
       // Clear all options from course select
       $("select#course option").remove();
       //put in a empty default line
       var row = "<option value=\"" + "" + "\">" + "Course" + "</option>";
       $(row).appendTo("select#course");
       // Fill course select
       $.each(data, function(i, j) {
        row = "<option value=\"" + j.id + "\">" + j.title + "</option>";
        $(row).appendTo("select#course");
       });
      }
     });
    }
   });

  });

Step - 4. Now add the courses js to application.js file bellow the jquery file.

# app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require courses
//= require_tree .

Step - 5. Here the course search form

# app/views/courses/course_search.html.erb

<div class="row no-gutters wow slideInUp" data-wow-duration="1s">
  <div class="col-md-12 home-form">
    <%= form_tag(course_search_path, method: "get", class: "form-inline", remote: true) do %>
    <%= select_tag "location", options_from_collection_for_select(Location.all, "id", "header"), prompt: "Location", class: "custom-select mb-0 mr-sm-0 mb-sm-0" %>
    <%= select_tag "course_type", options_from_collection_for_select(Course.all, "id", "course_type"), prompt: "Course Type", class: "custom-select mb-0 mr-sm-0 mb-sm-0" %>
    <%= select_tag "course", options_from_collection_for_select(Course.all, "id", "title"), prompt: "Course", class: "custom-select mb-0 mr-sm-0 mb-sm-0" %>
    <%= submit_tag("Search", class: "btn btn-primary") %>
<% end %>
  </div>
</div>

<div class="row" id="course_listing">
  <%= render partial: "course_list", locals: {courses: @courses} %>
</div>

Step - 6. Now you have to create a course_list partial file to display all courses

# app/views/courses/_course_list.html.erb
<% courses.each do |course| %>
  <%= course.id %>
  <%= course.title %>
  <hr />
<% end %>

Step - 7. Create a js view file for display courses for ajax search form submit.

# app/views/courses/course_search.js.erb
$('#course_listing').html('<%= j render partial: "course_list", locals: {courses: @courses} %>')

I hope it should work.

like image 108
Sahidur Rahman Suman Avatar answered Oct 27 '22 01:10

Sahidur Rahman Suman