I have a Rails view (recipes/new) which allows users to enter a new recipe. In that view, the user can select items from another model, ingredients. I wanted a way for the users to add a new ingredient without leaving the recipe form.
I created a link for new ingredients which loads a JQuery modal box. Here is the code in my recipes.js
file which drives the modal:
assets/javascripts/recipes.js
this code from @coreyward's answer - see Jquery modal windows and edit object for details - thanks, corey!
$(function(){
var $modal = $('#modal'),
$modal_close = $modal.find('.close'),
$modal_container = $('#modal-container');
$('a[data-remote]').live('ajax:beforeSend', function(e, xhr, settings){
xhr.setRequestHeader('accept', '*/*;q=0.5, text/html, ' + settings.accepts.html);
});
$('a[data-remote]').live('ajax:success', function(xhr, data, status){
$modal
.html(data)
.prepend($modal_close)
.css('top', $(window).scrollTop() + 40)
.show();
$modal_container.show();
});
$('.close', '#modal').live('click', function(){
$modal_container.hide();
$modal.hide();
return false;
});
});
My link in the recipes/new.html.erb:
<%= link_to 'New ingredient', new_ingredient_path, :remote => true %>
This works great, in the sense that it loads the modal form with the new ingredient form in there. I can fill out the form, and if the ingredient is saved, I call another function from my controller to close the modal:
ingredients_controller.rb
def create
if @ingredient.save
respond_to do |format|
format.js { render :js => "close_modal();" }
end
end
end
My problem is when the form is not filled out correctly. The user clicks and gets no feedback that there are any errors/missing fields, etc... I would like to reload the ingredient form in the popup box, which will render a shared errors partial:
ingredients/new.html.erb
<%= form_for @ingredient, :remote => true do |i| %>
<%= render 'shared/ingredient_error_messages' %>
<div class="field">
<%= i.label :name %>
<%= i.text_field :name %>
</div>
<div class="field">
<%= i.label :srm %>
<%= i.text_field :srm %>
</div>
<div class="field">
<%= i.label :price %>
<%= i.text_field :price %>
</div>
<div class="actions">
<%= i.submit "Save ingredient" %>
</div>
<% end %>
shared/_ingredient_error_messages.html.erb
<% if @ingredient.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@ingredient.errors.count, "error") %>
prohibited this recipe from being saved:</h2>
<p>There were problems with the following fields:</p>
<ul>
<% @ingredient.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
What's the best way to get this to work? I can easily create another JS function and call it from the controller if the save is not successful, but I can't find a way to pass in anything but straight text/html. Is there a way, in the controller, I can parse and output to a function the contents of my 'new' view? Is there a better/cleaner way to do this?
I have a Rails view (recipes/new) which allows users to enter a new recipe. In that view, the user can select items from another model, ingredients. I wanted a way for the users to add a new ingredient without leaving the recipe form.
I created a link for new ingredients which loads a JQuery modal box. Here is the code in my recipes.js
file which drives the modal:
assets/javascripts/recipes.js
this code from @coreyward's answer - see Jquery modal windows and edit object for details - thanks, corey!
$(function(){
var $modal = $('#modal'),
$modal_close = $modal.find('.close'),
$modal_container = $('#modal-container');
$('a[data-remote]').live('ajax:beforeSend', function(e, xhr, settings){
xhr.setRequestHeader('accept', '*/*;q=0.5, text/html, ' + settings.accepts.html);
});
$('a[data-remote]').live('ajax:success', function(xhr, data, status){
$modal
.html(data)
.prepend($modal_close)
.css('top', $(window).scrollTop() + 40)
.show();
$modal_container.show();
});
$('.close', '#modal').live('click', function(){
$modal_container.hide();
$modal.hide();
return false;
});
});
My link in the recipes/new.html.erb:
<%= link_to 'New ingredient', new_ingredient_path, :remote => true %>
This works great, in the sense that it loads the modal form with the new ingredient form in there. I can fill out the form, and if the ingredient is saved, I call another function from my controller to close the modal:
ingredients_controller.rb
def create
if @ingredient.save
respond_to do |format|
format.js { render :js => "close_modal();" }
end
end
end
My problem is when the form is not filled out correctly. The user clicks and gets no feedback that there are any errors/missing fields, etc... I would like to reload the ingredient form in the popup box, which will render a shared errors partial:
ingredients/new.html.erb
<%= form_for @ingredient, :remote => true do |i| %>
<%= render 'shared/ingredient_error_messages' %>
<div class="field">
<%= i.label :name %>
<%= i.text_field :name %>
</div>
<div class="field">
<%= i.label :srm %>
<%= i.text_field :srm %>
</div>
<div class="field">
<%= i.label :price %>
<%= i.text_field :price %>
</div>
<div class="actions">
<%= i.submit "Save ingredient" %>
</div>
<% end %>
shared/_ingredient_error_messages.html.erb
<% if @ingredient.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@ingredient.errors.count, "error") %>
prohibited this recipe from being saved:</h2>
<p>There were problems with the following fields:</p>
<ul>
<% @ingredient.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
What's the best way to get this to work? I can easily create another JS function and call it from the controller if the save is not successful, but I can't find a way to pass in anything but straight text/html. Is there a way, in the controller, I can parse and output to a function the contents of my 'new' view? Is there a better/cleaner way to do this?
Here is a link to a github Rails JQuery-Modal form that was designed by Ramblex to do this very thing:
https://github./ramblex/modal-form
Here is the respective SO question that it solved (so you can upvote his answer): Rails and modal jquery dialog form