简体   繁体   中英

Converting a select form to a dropdown buttons

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?

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

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.

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 %>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM