3

UPDATE: I'm almost there! See my partial answer at the end of this question.

I've got a working form with two select dropdowns, the first for countries, the second for cities. When you select a country, an ajax request automagically gets the countries and updates the countries box.

The problem is the select dropdowns are ugly, and I can't really style them. What I want is a dropdown button, which I can use Bootstrap on to make pretty: Bootstrap Button

I don't have to change the jquery or controller logic, I just have to update my view. But I don't even know where to start. This is what I have:

<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
  <%= f.select :country_obj_id, options_for_select(@countries.collect { |country|
    [country.name.titleize, country.id] }, @countries.first.name), {}, { id: 'countries_select' } %>
  <%= f.select :city_obj_id, options_for_select(@cities.collect { |city|
    [city.name.titleize, city.id] }, 0), {}, { id: 'cities_select' } %>
  <%= f.submit "Go!" %>
<% end %>

How can I convert the selects into dropdown buttons?


UPDATE: I can now get a response back. I just don't know how to handle it to update the button.

The view has two dropdown buttons. The first is the countries, the second is the cities for the first country. I want to update the list of cities for the country that is selected:

<div class="dropdown" style="display:inline-block;">
  <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A Country
  <span class="caret"></span></button>
  <ul class="dropdown-menu">
      <% @countries.each do |country| %>
        <%= content_tag(:li, link_to(country.name.titleize, update_cities_path(country_obj_id: country.id), remote: :true)) %>
      <% end %>
  </ul>
</div>
<div class="dropdown" style="display:inline-block;">
  <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A City
  <span class="caret"></span></button>
  <ul class="dropdown-menu">
      <% @cities.each do |city| %>
        <%= content_tag(:li, city.name.titleize) %>
      <% end %>
  </ul>
</div>

Selecting a country goes into the update_cities function, which gets the cities for the country_obj_id that is passed.

def update_cities
  @cities = CityObj.where("country_obj_id = ?", 
                           params[:country_obj_id]).order(:name)
  respond_to do |format|
    format.js
  end
end

Then the part that i don't understand. The format.js takes me to update_cities.js.coffee, which I have not changed from my original version that worked on the select dropdown:

$("#cities_select").empty()
  .append("<%= escape_javascript(render(:partial => @cities)) %>")

That ends up updating my old select dropdown, which I left in the view for now. But how can I modify the js to update my new dropdown button?

Terrytreks
  • 266
  • 3
  • 11

3 Answers3

2

You will need a mix of Javascript with Rails:

  1. First, you will need to print all options in Bootstrap's button format:
<div class="dropdown">
    <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Countries
    <span class="caret"></span></button>
    <ul class="dropdown-menu">
        <% @countries.each do |country| %>
            <%= content_tag(:li, country.name.titleize) %>
        <% end %>
    </ul>
</div>
  1. Add funcionality to select an option from this dropdown:

    https://stackoverflow.com/a/22000328/891807

Community
  • 1
  • 1
Daniel Lutz
  • 160
  • 1
  • 7
2

Got it. This is the coolest thing ever. It starts out with two buttons. The first says "Select A Country," and the second says "Select A City." The second button is not active to start with, and I'll probably hide it.

The view:

<div class="dropdown" style="display:inline-block;">
  <button id="country-select-btn" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A Country
  <span class="caret"></span></button>
  <ul class="dropdown-menu">
      <% @countries.each do |country| %>
        <%= content_tag(:li, link_to(country.name.titleize, update_cities_path(country_obj_id: country.id), remote: :true)) %>
      <% end %>
  </ul>
</div>
<div class="dropdown" style="display:inline-block;">
  <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A City
  <span class="caret"></span></button>
  <ul id="cities_select" class="dropdown-menu">
  </ul>
</div>

The dropdown items are just links, with a route set so clicking a link goes to the controller update_cities action with a country passed:

def update_cities
  @cities = CityObj.where("country_obj_id = ?", 
                           params[:country_obj_id]).order(:name)
  @country = CountryObj.find_by(id: params[:country_obj_id])

  respond_to do |format|
    format.js
  end
end

The format.js goes into update_cities.js

$("#cities_select").empty()
  .append("<%= escape_javascript(render(:partial => @cities)) %>")

$("#country-select-btn").empty()
  .append("<%= escape_javascript(render(:partial => @country )) %>")

That renders two partials. _city_obj.html.erb renders a link for each of the cities, which will go to the controller's index action when clicked:

<li><%= link_to(city_obj.name.titleize, index_path(:trip => {country_obj_id: city_obj.country_obj.id, city_obj_id: city_obj.id}), id: "cities_select") %></li>

The _country_obj.html partial just updates the "Select A Country" label on the button to the name of the selected country:

<%= country_obj.name.titleize %>

Now, when you click one of the city links, the controller index action can find all the guides for that city/country, then the view will render it.

Terrytreks
  • 266
  • 3
  • 11
  • congratz, dude... just one thing: you don't need to append Obj to each one of your models, hehehe – Daniel Lutz Nov 17 '15 at 10:38
  • True, @DanielLutz. The reason I did that was my first implementation was to use simple strings for country and city. So I had city/country strings and CityObjs and CountryObjs. The strings are gone now, so I should drop the Obj from the names... – Terrytreks Nov 18 '15 at 15:35
0

From what I understood, you want to add style to your html form using bootstrap. If this is the case then this is how you can do that:

1.Add bootstrap gem if you have not done it already following the documentation(https://github.com/twbs/bootstrap-sass) In short, you need to add following at your Gemfile:

gem 'bootstrap-sass', '~> 3.3.5'

Add following line at your app/assets/stylesheets/application.scss so that bootstrap styles gets added at every page:

@import "bootstrap-sprockets";
@import "bootstrap";

2.Using bootstrap styles, at your ugly select tag you need to add form-control at your class name as bootstrap documentation suggests. add class: "form-control" parameter like this:

<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
  <%= f.select :country_obj_id, options_for_select(@countries.collect { |country|
    [country.name.titleize, country.id] }, @countries.first.name), {}, { id: 'countries_select', class: "form-control" } %>
  <%= f.select :city_obj_id, options_for_select(@cities.collect { |city|
    [city.name.titleize, city.id] }, 0), {}, { id: 'cities_select', class: "form-control" } %>
  <%= f.submit "Go!" %>
<% end %>
sadaf2605
  • 7,332
  • 8
  • 60
  • 103
  • I will try this, but my understanding is it isn't possible to do much styling to select elements. In fact, the Bootstrap doc says "Avoid using – Terrytreks Nov 10 '15 at 15:07
  • avoid using – sadaf2605 Nov 11 '15 at 11:33