Adding javascript handlers to remote form object after injection with RJS - ruby-on-rails

I have a page form, where i want the user to add nested forms by clicking on a remote link ('add photo', f. ex). Upon clicking the button I inject the nested forms with RJS. The injected forms are remote forms, but after injection the forms have no javascript events attached so they just submit with http to the controller of the nested object. Beside that, everything works fine.
My question is:
Is it possible to trigger revalidation of javascript of remote forms via RJS, after injection??
That way my nested forms would get the proper javascript event handling and submit with AJAX.
My page form (_form.html.erb):
<% javascript 'ckeditor/ckeditor' %>
<%= form_for #page, :html => { :multipart => true } do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :active %><br />
<%= f.check_box :active %>
</p>
<p>
<%= f.label :homepage %><br />
<%= f.check_box :homepage %>
</p>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description, :rows => 5, :cols => 80 %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text, :class => 'html' %>
</p>
<p>
<%= f.label :picture_class %><br />
<%= f.select :picture_class, ['left','right','full'] %>
</p>
<% unless #page.new_record? %>
<h2>Photos</h2>
<%= link_to 'Add photo', add_photo_page_url(#page), :remote => true %>
<div id="photos">
<%= render :partial => 'shared/forms/photo', :collection => #page.photos %>
</div>
<h2>Snippets</h2>
<%= link_to 'Add snippet', add_snippet_page_url(#page), :remote => true %>
<div id="snippets">
<%= render :partial => 'shared/forms/photo', :collection => #page.snippets %>
</div>
<h2>Downloads</h2>
<%= link_to 'Add download', add_download_page_url(#page), :remote => true %>
<div id="downloads">
<%= render :partial => 'shared/forms/download', :collection => #page.downloads %>
</div>
<h2>Paragraphs</h2>
<%= link_to 'Add paragraph', add_paragraph_page_url(#page), :remote => true %>
<div id="paragraphs">
<%= render :partial => 'shared/forms/paragraph', :collection => #page.paragraphs %>
</div>
<% end %>
<p><%= f.submit %></p>
<% end %>
<%= javascript_tag 'CKEDITOR.replaceAll("html");' %>
Controller code to build the nested photo object: (page_controller.rb):
def add_photo
#page = Page.find(params[:id])
#photo = #page.photos.build
end
RJS code that gets executed by clicking 'add photo' (add_photo.js.rjs):
page.insert_html :bottom, :photos, :partial => 'shared/forms/photo', :object => #photo
page.visual_effect :highlight, :photos, :duration => 2
The partial/form that gets injected with RJS (_photo.html.erb):
<%= form_for [#page, photo], :remote => true do |f| %>
<p>
<%= f.check_box :active %>
<%= f.text_field :name %>
<%= f.file_field :photo %>
<%= f.submit 'Save' %>
</p>
<% end %>
Any help would be appreciated. I would like to solve this with nested forms (not nested attributes) and RJS, but was unable to google my way to documentation on this.
Thanks!!
-- Jakob

If you want to stick with RJS, you'll need to look into the built-in javascript to see how they're registering everything. They probably just do it on DOM ready and bind to the submit() event. It's most likely encapsulated in a method which looks for anything marked :remote => true and binds to the submit() event so it will submit via AJAX. You can execute the same logic but isolate it to your new form. So maybe your partial could have a JavaScript tag which executes that logic for that form, based on the id, or based on the classname, ignoring everything but the most recently added form.

Related

Render partial after change select

I have the following view
<%= form_for #survey do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %> <br><br>
<%= f.label :description %><br>
<%= f.text_field :description %><br><br>
</div>
<%= f.fields_for :survey_sections do |builder| %>
<%= builder.text_field :title, :placeholder => "Abschnittsbeschreibung" %><br>
<%= builder.fields_for :questions do |quest| %>
<%= quest.text_field :text, :placeholder => "Frage" %> <br>
<%= quest.fields_for :answers do |ans| %>
<%= ans.text_field :text, :placeholder => "Antwort" %> <br>
<%end%>
<%end%>
<%= select_tag("question_type",options_for_select([["Radio", "radio"],["Checkbox", "check"]])) %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I want to render a partial in this view after selecting one of the options.
How can i do this?
Easiest way is render the partial with display:none
<div id='foo' style='display:none'>
<%= render :foobar %>
</div>
And when a user select something, show it by JS(jQuery).
$('[name=question_type]').change(function() {
$('#foo').show();
});
If you are using jQuery, then try this:
VIEW
<%= select_tag("qustion_type",options_for_select([["Radio", "radio", {:onclick => "someFunction(#{controller_path})"}],["Checkbox", "check", {:onclick => "someFunction(#{controller_path})"}]])) %>
JAVASCRIPT
function someFunction(url) {
jQuery.ajax({
url: url,
data: {some_data: "data_value"},
success: function(data) {
//data has the html code that you render in controller
}
});
}
EDIT (See Comments)
As you asked that you need to render a partial on each option select. So, for each option select you need to hit a controller method. In my example url is that controller end point(eg:- render_radio_some_controller_path).
def render_radio
render :partial => "radio"
end
After this, it will go to the success block of Ajax call and data will have the html defined in radio.html.erb. Now, you just have to use jQuery to update the desired div html with data(Eg:- jQuery("#some_div").html(data);)

Extend forms without page reload, rails

I'm searching for a solution to extend my form without page reload.
First I tried to render a partial with coffee or javascript, but escape_javascript didnt work.
Here's the view
<%= form_for #recipe = current_user.recipes.build do |f| %>
<%= f.label :name, "Recipe Name" %>
<%= f.text_field :name %>
<%= button_to "Add Ingredient", '#', class: "btn btn-lg btn-primary", id: "add" %>
<p></p>
<%= f.submit class: "btn" %>
<% end %>
The form above should be extented with following partial by every click on the button
<div id="recipe-ingredients">Quantity
<%= f.fields_for :quantities, #recipe.quantities.build do |quantity| %>
<%= render 'quantity_fields', f: quantity %>
<% end %>
</div>
_quantity_fields
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
This approach did not work (recipes.js.erb)
$(document).ready(function() {
$("#add").click(function() {
$("p").append("<%= escape_javascript
render(:partial => 'quantities') %>");
});
});
There's a workaround (see below) but I'm searching for a better solution.
$(document).ready(function() {
$("#workout-week").append(<%= escape_javascript(
Haml::Engine.new(File.read(File.join(Rails.root,'app/views',
'_show_period.html.haml'))).render(Object.new, period: #period)) %>);
});
A second approach is to write following lines in Coffee or JavaScript:
<%= f.fields_for :quantities, #recipe.quantities.build do |quantity| %>
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
<% end %>
I'm a newbie so take this with a grain of salt, but have you tried using render :foo instead of redirect_to :foo in the appropriate controller function?
I solved it with cocoon
<%= form_for #recipe do |f| %>
<div class="field">
<%= f.label :name %>
<br/>
<%= f.text_field :name %>
<%= f.fields_for :quantities do |quantity| %>
<%= render 'quantity_fields', :f => quantity %>
<% end %>
<div class="links">
<%= link_to_add_association 'add', f, :quantities %>
</div>
</div>
<%= f.submit %>
<% end %>

Form not updating values in the database if the class of a framework is used

I m using the ink framework for styling my web application. And for styling form i am using this http://ink.sapo.pt/index.php/forms.
<form class= "ink-form inline">
<%= form_for(#document, :remote => true) do |f| %>
<fieldset>
<div class="control required validation error">
<%= f.label :title, :class => "short" %>
<%= f.text_field :title, :class => "short" %>
</div>
</fieldset>
<% end %>
</form>
In the above form ive put the class= ink-form inline to style the form. Doing this styles my form but it does nt update the values in the database. When i use this code
<%= form_for(#document, :remote => true, :class => "ink-form inline") do |f| %>
then it updates the values in the database but it doesnt style the form. I am not getting where the problem is. Please help.!!
Try this!
<%= form_for(#document, :remote => true, :html => {:class => "ink-form inline"}) do |f| %>
<fieldset>
<div class="control required validation error">
<%= f.label :title, :class => "short" %>
<%= f.text_field :title, :class => "short" %>
</div>
</fieldset>
<% end %>
If you had inspected your earlier code in the browser, you would see two form tags (one within the other). The reason is form_for generates its own form and that is where you would want to provide the options.

ruby on rails select not defaulting to current value

I'm currently using a select as follows (within a form):
<% form_for :search, :url => search_path, :html => {:method => :get} do |f| %>
<%= select('search', :type, options_for_select(['Artist', 'Track'])) %>
<%= f.text_field :query %>
<% end %>
This works, but when I perform a search, it defaults back to artist even if the user selected Track before searching. How can I correct this?
Automatically selecting the current value works for radio buttons:
<% form_for #search, :url => search_path, :html => {:method => :get} do |f| %>
<p class="radio_button">
<%= f.label :type_track, 'Search tracks' %>
<%= f.radio_button :type, 'Track' %>
</p>
<p class="radio_button">
<%= f.label :type_artist, 'Search artists' %>
<%= f.radio_button :type, 'Artist' %>
</p>
<p class="text_field">
<%= f.label :query, 'Search query' %>
<%= f.text_field :query, :class => 'auto_focus' %>
</p>
<p class="submit">
<%= submit_tag 'Go' %>
</p>
<% end %>
Any help getting this to work will be greatly appreciated!
You must use the select form builder:
<%= f.select(:type, [["text1", "value1"], ["text2", "value2"], ...]) %>

Work after user creation

I create a new user with basic fields as user name and password. Then I redirect to another page where the user is allowed to complete his profile. The page looks like this.
Ok, I created the user first. Then I redirected the user to complete his profile. The profile page looks like this
<h1>User successfully created</h1>
<h3>Would you like to complete your profile now?</h3>
<%= render #profile %>
<%= render #address %>
<%= button_to 'Save',{
:controller => "users",
:action => "update",
:id => #user.id,
:profile => #profile,
:address => #address
}, :method => :put %>
The code above executes the update action in the controller. However, I am getting nil for the #profile and #address objects. I guess the button_to is having no effect on the profile and address partials.
The address partial looks as follows
<%= form_for(#address) do |f| %>
<% if #address.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#address.errors.count, "error") %> prohibited this address from being saved:</h2>
<ul>
<% #address.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<fieldset>
<legend>Addresss</legend>
<div class="field">
<%= f.label :street_address %>
<%= f.text_field :street_address, :size => 40 %>
</div>
<div class="field">
<%= f.label :street_address_2 %>
<%= f.text_field :street_address_2, :size => 40 %>
</div>
<div class="field">
<%= f.label :city %>
<%= f.text_field :city, :size => 40 %>
</div>
<div class="field">
<%= f.label :state %>
<%= f.text_field :state, :size => 40 %>
</div>
<div class="field">
<%= f.label :zip_code %>
<%= f.text_field :zip_code, :size => 40 %>
</div>
<% end %>
I would appreciate if anyone would be able to help me on this.
The button_to method only creates a button which an be used to call an controller/ go to another page.
If you want to allow the user to modify fields, you need to use a form. Please read this guide on forms for more information, especially part 2 is of interest for your situation I guess.
Edit: You need a submit button in your form to submit it, not a button_to outside the form. If you want to have both partials submitted at the same time, you need 1 big form and a controller which is able to process the data of both models.

Resources