I'm asking about using a Twitter Bootstrap modal window with a Rails form helper and displaying form validation error messages. I'm using Twitter Bootstrap 2.0 with Rails 3.2.
I've got a form inside a Twitter Bootstrap modal window. There's a button on the page to open the modal window and display the form. All good, except when the form is submitted with errors, the page is displayed and error messages can't be seen because the form is inside the (initially undisplayed) modal window.
I need to use jQuery to test if the form contains a Rails error message and override the "display: none;" style (or toggle the modal window to display) when the page is rendered.
I've tried adding the following code to my assets/javascripts/application.js file but it doesn't work:
$('document').ready(function() {
if ($('#error_explanation').length > 0) {
$("#request_invite").css("display", "block");
}
})
and also:
$('document').ready(function() {
if ($('#error_explanation').length > 0) {
$("#request_invite").modal('toggle');
}
})
What do I need to do to display the modal window or toggle it open when there's an error message present?
Here's the code that displays the form inside the Twitter Bootstrap modal window (Haml):
#request-invite.modal{:style => "display: none;"}
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
.modal-header
%a.close{"data-dismiss" => "modal"} ×
%h3 Request Invitation
.modal-body
- if @user.errors.any?
#error_explanation
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
%p
= f.label :email
%br/
= f.email_field :email
.modal-footer
= f.submit "Request Invitation", :class => "btn.btn-success"
%a.btn{"data-dismiss" => "modal", :href => "#"} Close
#romance-copy{:style => "text-align: center; margin-top: 100px"}
%h2 Want in?
#call-to-action{:style => "text-align: center; margin-top: 100px"}
%a.btn.btn-primary.btn-large{"data-toggle" => "modal", :href => "#request-invite"} Request invite
Looks like a typo? Your div in Haml has the ID request-invite (with a dash). However, your jQuery is looking for an ID with an underscore.
I want to offer another option. The way you use should work, but why not just use AJAX to show the error msg when there is any error. What the response JS does is to add the extra styles to show the error msg.
I need to use jQuery to test if the form contains a Rails error message and override the "display: none;" style (or toggle the modal window to display) when the page is rendered.
Take a look at http://www.twitmark.me/. Try sign in with twitter. Input a faked invitation code and see what the error looks like. Is this a better solution?
<div>
with the error
class and add the inline-help
object? How do you trigger the reload--from JQuery? What does the controller do on failure? I feel like I've got most of the pieces but am having trouble stitching them together - Mark Berry 2012-11-14 03:23
format.json { render json: @invitation.error, status: :unprocessable_entity }
. But I also saw an example that had the JSON response and added something like this: format.js {render 'create' }
. But it looks like your code would not need format_json
at all, right - Mark Berry 2012-11-15 01:55
As stated by @wanghq (and in part by @miked), I think the best way is to use AJAX to render the html in the modal and submit the form data. This way, all the logic is delegated to server side, using JS only for the effects and keeping views clean (no helpers nor logic involved inside views).
with this solution is that you can gracefully degrade when JS doesn't work on the client by using same controller action to render the form. A simple example:
def new
@user = User.new
# some stuff...
render :handler => 'haml', :layout => !request.xhr?
end
# similar logic should be used for #create action
for the (d)html part, you might use ruby to detect if it should be displayed because of errors. I mean something like this (you might write an helper if needed):
#request-invite.modal{:style => "display: #{ @user.errors.any? ? 'block' : 'none' };"}
as a side note, using simple_form 2.0.x, you'll get twitter-bootstrap markup support (I mean, it will generate bootstrap-friendly markup for your forms). In this way, you'll DRY some logic inside templates (eg: checking @user.errors to diplay error messages)
in this way, you should not need JS to do checks ;)
my 2cents ;-)
I might be misunderstanding the problem, but from what I can see, your error_explanation div isn't hidden (display:none) when the modal loads, it doesn't exist because it's conditioned in the if @user.errors.any? block. Therefore it won't matter what javascript you throw at it, it's not there.
For starters, try:
.modal-body
#error_explanation
- if @user.errors.any?
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
this way, the div will exist and the ul will only show items if their are errors to display.
Why do you need jQuery? Why not just use the conditional you already have?
This code sucks, you could probably clean it up (move it into helper or something), but you'll get the idea.
- def display?; @user.errors.any? ? "block;" : "none;"; end;
#request-invite.modal{:style => "display: " + display? }
$('<div class="modal-backdrop"/>').appendTo(document.body)
mwoods79 2012-04-04 23:02