Twitter Bootstrapping a locale selector drop-down

2019-09-19 01:27发布

问题:

I have a non-Bootstrapped locale selector in my otherwise generally Bootstrapped Rails 3 app that I want to Bootstrap-ify. I'm a bit stumped as to how to make an (I assume) unordered list in a form in a dropdown menu.

TL;DR Go to Edit 3 at the bottom of this question for the completed solution.

The current code is implemented in the following way:

app/views/layouts/_header.html.haml

%header.navbar.navbar-fixed-top
  .navbar-inner
    .container
      # ...
      %nav
        %ul.nav.pull-right
          # ...
          %li= render 'layouts/locale_selector',
                       controller: controller, 
                       action: action
          # (controller, action params passed in from application.html.haml)

app/views/layouts/_locale_selector.html.haml

= form_tag({ controller: controller,
             action: action },
             method: 'get',
             class: 'locale') do
  = select_tag 'set_locale',
               options_for_select(locale_languages, I18n.locale)
  = hidden_field_tag 'page', params[:page] if params[:page]
  = submit_tag 'submit'

app/helpers/application_helper.rb

module ApplicationHelper
  # ...
  def locale_languages
    [
      [t('locale_selector.en'), 'en'],
      [t('locale_selector.it'), 'it'],
      [t('locale_selector.ja'), 'ja']
    ]
  end
end

app/assets/stylesheets/bootstrap_and_overrides.css.scss

# ...
.locale {
  padding-top: 5px;
  padding-left: 5px;
  margin: -0.25em;
  #set_locale {
    width: 85px;
    height: 36px;
    color: $grayLight;
    border: none;
    background: none;
    text-align: center;
    &:hover {
      color: $white;
      text-decoration: none;
    }
  }
}

app/assets/javascripts/application.js.coffee

$ ->
  $(".locale input").hide()
  $("#set_locale").change ->
    $(this).closest("form").submit()

By reading through the Bootstrap component documentation I've changed header.html.haml to the code below to get the drop-down list displaying how I want, but it's getting the content in the select_tag, options_for_select etc displaying/working correctly that I'm not sure about:

app/views/layouts/_header.html.haml

# ...
%li#fat-menu.dropdown
  %a.dropdown-toggle{"data-toggle" => "dropdown", href: "#"}
    = t('.language')
    %b.caret
  .dropdown-menu
    = render 'layouts/locale_selector',
              controller: controller,
              action: action

I've tried to find info in the Bootstrap documentation on forms and by searching around StackOverflow and Google, but to no avail. I bet I'm missing something simple and/or trivial, but could any Bootstrap experts help me out?

Edit

Changed 2 files to get the drop-down looking nice, but it still doesn't submit yet...

app/helpers/application_helper.rb

module ApplicationHelper
  # ...
  def locale_languages
    [
      { label: t('locale_selector.en'), locale: 'en' },
      { label: t('locale_selector.it'), locale: 'it' },
      { label: t('locale_selector.ja'), locale: 'ja' }
    ]
  end
end

app/views/layouts/_locale_selector.html.haml

= form_tag({ controller: controller,
             action: action },
             method: 'get',
             class: 'locale') do
  - locale_languages.each do |language|
    %li= link_to language[:label], '#', value: language[:locale]
  = hidden_field_tag 'page', params[:page] if params[:page]
  = submit_tag 'submit'

Edit 2

app/assets/javascripts/application.js.coffee

$ ->
  $(".locale input").hide()
  $(".locale").click ->
    $(this).closest("form").submit()

Now it submits, but all my original backend handling of the params[:set_locale] in my ApplicationController is broken (won't put the code here, but for the curious here it is), so the locale doesn't change. Need to try and get this to pass back a params[:set_locale] value...

Edit 3: The Completed Solution

Got rid of the form entirely, which I should have done in the first place as pointed out by @simbirsk and @quick_brown_fox. Many thanks, guys. Here is the final code:

app/views/layouts/_header.html.haml

%header.navbar.navbar-fixed-top
  .navbar-inner
    .container
      # ...
      %nav
        %ul.nav.pull-right
          # ...
          %li= render 'layouts/locale_selector',
                       controller: controller, 
                       action: action
          # (controller, action params passed in from application.html.haml)

app/views/layouts/_locale_selector.html.haml

%li#fat-menu.dropdown
  %a.dropdown-toggle{"data-toggle" => "dropdown", href: "#"}
    = t('.language')
    %b.caret
  %ul.dropdown-menu
    - locale_languages.each do |language|
      %li
        = link_to language[:label],
                  controller: controller,
                  action: action,
                  set_locale: language[:locale],
                  page: params[:page]

app/helpers/application_helper.rb

module ApplicationHelper
  # ...
  def locale_languages
    [
      { label: t('locale_selector.en'), locale: 'en' },
      { label: t('locale_selector.it'), locale: 'it' },
      { label: t('locale_selector.ja'), locale: 'ja' }
    ]
  end
end

Code mentioned above in app/assets/stylesheets/bootstrap_and_overrides.css.scss and app/assets/javascripts/application.js.coffee was completely removed as it became superfluous.

Update: This seems to be getting a lot of views, so:

  • You can find the full implementation of the locale drop-down, including the code in the controller here in the app I made for Michael Hartl's Rails Tutorial

回答1:

Your <select> solution looks great, but unfortunatelly that's not Bootstrap native.
As said in documents, markup for a navbar dropdown is as follows:

<div class="dropdown">
    <a class="dropdown-toggle" id="dLabel" role="button" data-toggle="dropdown" data-target="#" href="/page.html">
        Language
        <b class="caret"></b>
    </a>
    <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
        <li><a href="#">English</a></li>
        <li><a href="#">Portuguese</a></li>
        ...
    </ul>
</div>

So, if you want to stay "Bootstraped", adapt your code and generate (dinamically, if you wish) a collection of <li> containing links to each language. You can post any data you need using <%= link_to %>



回答2:

I don't think there's a way to style a <select> element as a dropdown via Bootstrap. Instead of using a form, how about using links in an unordered list and maybe changing your controller a little bit?

Or – if that's no solution, you probably will have to use some JavaScript magic or create some kind of POST link (I'm not so much into Rails right now to remember exactly how you do that, but you can, right?)

(Not sure if I got your question right …)