Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
597 views
in Technique[技术] by (71.8m points)

javascript - Twitter Bootstrap Rails button dropdown no responding to AJAX

I have a Rails 4 app that is using Bootstrap. I am creating a dashboard page that shows buttons that are color coded to represent the status of the tool it represents. The HTML in the page looks like this:

<div class="btn-group">
   <a class="btn custombutton dropdown-toggle btn-success" data-toggle="dropdown" href="#" id="btn0" >
      706-Hydraulic Ram<br> 98061841
   </a>

   <ul class="dropdown-menu">
       <li><a data-method="post" data-remote="true" href="/update_in_service?id=32" id="in_service" rel="nofollow">In Service</a></li>
       <li><a data-method="post" data-remote="true" href="/update_out_service?id=32" id="out_service" rel="nofollow">Out of Service</a></li>
       <li><a href="/tools/32">view Details</a></li>
   </ul>
</div>

The two methods linked to look like this:

def in_service
 @tool.update(:in_service => true)
 respond_to do |format|
   format.html { redirect_to(root_path) }
   format.js
   end
end


def out_service
  @tool.update(:in_service => false)
  respond_to do |format|
    format.html { redirect_to(root_path) }
    format.js
  end
end

Since there is nothing after the "format.js" Rails should automatically execute a file that has the same name as the method followed by .js.erb. so I have a in_service.js.erb and an out_service.js.erb file. They look like this:

$('.in_service').bind('ajax:success', function() {
    $(this).closest('.btn').addClass('.btn-success').removeClass('.btn-warning');
});


$('.out_service').bind('ajax:success', function() {
    $(this).closest('.btn').addClass('.btn-warning').removeClass('.btn-success');
});

I don't get any errors on the JS console in the browser when I click on the drop down links. The controller part is working perfect. If I reload the page it will show the button with the modified color. The rails server log shows this:

SQL (8.3ms)  UPDATE "tools" SET "in_service" = $1, "updated_at" = $2 WHERE "tools"."id" = 32  [["in_service", false], ["updated_at", Wed, 28 Aug 2013 22:28:11 PDT -07:00]]
   (1092.8ms)  COMMIT
  Rendered tools/out_service.js.erb (0.6ms)
Completed 200 OK in 1383ms (Views: 259.3ms | ActiveRecord: 1104.3ms)

So it's actually "rendering" the JS file but the page never changes. I've tried many different jquery selectors to see if it was a problem with that, but came up with the same results. My application.js file has these includes:

//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require bootstrap-datepicker
//= require server-time
//= require jquery-table
//= require_tree .

I've searched just about everything I can think of and am still stumped. I am terrible at JS and my understanding of it is pretty rudimentary. Thanks.

Edit ----

So I made the changes suggested by HAWK but something about it doesn't work with my setup. I get this in the Chrome JS console:

POST http://localhost:3000/update_in_service?btn_id=btn0&id=29&in_service=false 500    (Internal Server Error)                          jquery.js?body=1:8725
send                           jquery.js?body=1:8725
jQuery.extend.ajax                           jquery.js?body=1:8155
$.rails.rails.ajax                           jquery_ujs.js?body=1:73
$.rails.rails.handleRemote                           jquery_ujs.js?body=1:149
(anonymous function)                           jquery_ujs.js?body=1:299
jQuery.event.dispatch                           jquery.js?body=1:5117
elemData.handle                           jquery.js?body=1:4788

and in the web server log:

Completed 400 Bad Request in 10ms

ActionController::ParameterMissing - param not found: tool:

It's as if it is no longer getting the :tool parameter which is required as I am on Rails 4 using strong params. The data side of everything was working under my old code, the only thing that wasn't happening was the javascript update of the css style on the element. I rolled my code back to the original and when I click on the drop down menu the web server shows:

Started POST "/update_in_service?id=29" for 127.0.0.1 at 2013-08-29 10:28:11 -0700
Processing by ToolsController#in_service as JS
Parameters: {"id"=>"29"}
Tool Load (0.5ms)  SELECT "tools".* FROM "tools" WHERE "tools"."id" = $1 LIMIT 1  [["id", "29"]]
(0.2ms)  BEGIN
SQL (0.7ms)  UPDATE "tools" SET "in_service" = $1, "updated_at" = $2 WHERE "tools"."id" = 29  [["in_service", true], ["updated_at", Thu, 29 Aug 2013 10:28:11 PDT -07:00]]
(1245.5ms)  COMMIT
Rendered tools/in_service.js.erb (0.6ms)
Completed 200 OK in 1266ms (Views: 6.1ms | ActiveRecord: 1249.5ms)

I even changed the .js.erb files to target one of the buttons directly by ID to make sure it wasn't a selector problem:

$('#btn7').addClass('.btn-success').removeClass('.btn-warning');

I saw a link about something in bootstrap or rails stopping the JS from ever being executed in a bootstrap drop down but am still trying to find the link. Thanks for all the help so far.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So I finally figured this one out. The key was having the workflow down: :remote => true connects to the toggle_in_service method in the controller that then calls the toggle_in_service.js.erb file which finally calls toggle_button.html.erb. I also found that when working in Bootstrap it's probably best to try and target an existing <div> for replacement rather than wrap a piece of bootstrap code in another div. Not sure on that but it seemed to matter. Here is the code that worked:

dashboard.html.erb view snippet:

 <% status_link = tool.in_service ? "Put Out of Service" : "Put In Service" %>
 <% button_link = "#{tool.location}-#{tool.name.singularize}"+'<br>'+" #{tool.serial}" %>
 <div class="btn-group" id="btn<%= tool.id %>" >

    <a class="btn custombutton dropdown-toggle <%= (tool.in_service  ? 'btn-success' : 'btn-warning') %>" data-toggle="dropdown" href="#"  >
      <%=  raw(button_link) %>
    </a>

    <ul class="dropdown-menu">
      <li><%= link_to status_link, toggle_in_service_path(:id => tool.id), :method => :post, :remote => true %></li>
      <li><%= link_to "view Details", tool_path(tool.id) %></li>
    </ul>
 </div>

This creates a Bootstrap dropdown menu attached to a button that is color coded by the status of the tool.

The first link in the dropdown menu is a remote ajax call to the toggle_in_service controller, passing the tool.id paramter. The controller method looks like:

def toggle_in_service
   status_change = @tool.in_service ? false : true
   @tool.update(:in_service => status_change)
   respond_to do |format|
     format.html { redirect_to(@tool) }
     format.js
  end
end

The boolean value for tool.in_service gets flipped and then calls toggle_in_service.js.erb:

<% btn_id = "btn#{@tool.id}" %>

$('#<%=btn_id%>').html('<%= escape_javascript(render :partial => "toggle_button") %>');

Which does an AJAX render of the _toggle_button.html.erb partial:

<% button_link = "#{@tool.location}-#{@tool.name.singularize}"+'<br>'+" #{@tool.serial}" %>
<% status_link = @tool.in_service ? "Put Out of Service" : "Put In Service" %>

<a class="btn custombutton dropdown-toggle <%= (@tool.in_service  ? 'btn-success' : 'btn-warning') %>" data-toggle="dropdown" href="#"  >
  <%=  raw(button_link) %>
</a>
<ul class="dropdown-menu">
  <li><%= link_to status_link, toggle_in_service_path(:id => @tool.id), :method => :post, :remote => true %></li>
  <li><%= link_to "view Details", tool_path(@tool.id) %></li>
</ul>

Works great! The entire div for the dropdown and the button get updated by AJAX. I'm posting this in case someone looks for something similar. I search many hours on the web and on Stack Overflow, but never found what I needed. I did some reading up on Rails AJAX to figure out what I was doing wrong.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...