User-editable table with variable number of rows in Rails - javascript

I'm running Rails 3.2.11. I'm working on a simple wiki project as I learn Rails and Javascript. What I want to do is store a two-column table in my database whose contents and number of rows can be edited by users, and use jQuery to add forms for a new table row on a button click. The table is stored as a hash containing hashes for each row's columns. i.e. {"row1" => {"head" => "first column/header content", "tail" => "second column/data content"}, "row2" => {"head" => "first column/header content", "tail" => "second column/data content"}} The part of my _form.html.erb for editing the table looks like this:
<div id="node_table_row_0">
<%= f.fields_for :table do |table_rows| %>
<%= table_rows.fields_for :row do |table_cols| %>
<%= table_cols.text_field :head, :id => 'node_table_row_head_0' %>
<%= table_cols.text_field :tail, :id => 'node_table_row_tail_0' %>
<% end %>
<% end %>
<button id="add_table_row" type="button" class="btn btn-small">Add Row</button>
</div>
I'm displaying the table on my page like so:
<table class="table">
<% #node.table.each do |row| %>
<tr>
<th><%= row[1]['head'] %></th> <td><%= row[1]['tail'] %></td>
</tr>
<% end %>
</table>
And my node.js file contains the following:
$(document).ready(function(){
$('#header').append('Script loaded')
var newIndex = 0
$('#add_table_row').click(function(){
$('.sidebar_img').append('onclick event activated')
var prevIndex = newIndex
var prevRow = $('#node_table_row')
newIndex = newIndex + 1
var newRow = prevRow.clone(true).attr('id', 'node_table_row_'+newIndex)
newRow.find('#node_table_row_head').attr({ id: 'node_table_row_head_'+newIndex, name: 'node[table][row'+newIndex+'][head]'})
newRow.find('#node_table_row_tail').attr({ id: 'node_table_row_tail_'+newIndex, name: 'node[table][row'+newIndex+'][tail]'})
newRow.after(prevRow)
});
});
When I click the "add row" button, I get my confirmation that the onclick event has been recognized, but the forms are not appended. Am I approaching this entirely the wrong way? It seems like there would be a simpler way to go about this.

Have you tried using the jQuery insertAfter() method? use jQuery to select the table then use .children().insertAfter(newRow);

Related

How can I get the dynamic Id of nested form?

I got the following code, which I want to show the Add option button when the user chooses the OPTIONS type in the select box. It only works for the first time to add the question. I know the problem which is I gave the id to the select box, but if I do not do that, how can I get the dynamic id of the select box?
<%= f.fields_for :questions do |question_form| %>
<%= question_form.text_field :question_text %>
<%= question_form.select(:question_type, [ 'TEXT', 'OPTIONS', 'UPLOAD' ],{:prompt => 'Select One'}, :id => "my_id", :onchange => "myFunction()") %>
<%= question_form.link_to_remove "Remove this Question" %>
<%= question_form.fields_for :options do |option_form| %>
<%= option_form.text_field :option_text %>
<%= option_form.link_to_remove "Remove this option" %>
<% end %>
<p id = "test" hidden><%= question_form.link_to_add "Add a option", :options %></p>
<% end %>
<p><%= f.link_to_add "Add a Question", :questions %></p>
<p>
<%= f.submit %>
</p>
<% end %>
<script>
function myFunction(){
var e = document.getElementById("my_id");
var x = e.options[e.selectedIndex].value
if (x == "OPTIONS"){
document.getElementById("test").hidden = false;
}
else{
document.getElementById("test").hidden = true;
}
}
</script>
While I'm not entirely sure what you mean by "It only works for the first time to add the question", it sounds like you're confident that using document.getElementById() is the problem. (I don't know why it would be, but I'm unfamiliar with Rails, so I'll assume you're correct.)
If so, you can avoid that selector by using the target property of the EventListeners's built-in "event" parameter:
function myFunction(event){
`var x = event.target.options[e.target.selectedIndex].value`
...
(And you might be able to shorten this to event.target.value.)

Individual JavaScript for multiple records in Rails

I've been trying to wrap my head around this for days now, but I can't seem to find a solution for this problem.
Basically what I want to do is a feed similar to Facebook. A feed with multiple posts, of which each has comments/replies.
Now what I can't get to work is an AJAX "Load more" button for each post. I've only got it working for all posts at once, but not for individual ones.
What I have so far:
The feed:
<% #posts.each do |post| %>
<%= render "posts/thread", post: post %>
<% end %>
The threads:
<%= render post %>
<% replies = post.replies.paginate(:page => params["replies#{post.id.to_s}"], :per_page => 2) %>
<%= render replies %>
<%= will_paginate replies, :param_name => 'replies'+post.id.to_s %>
<%= link_to "Load More", "#", class: "load-more", id: post.id, :remote => true %>
The posts:
<div class="post" data-id="<%= post.id %>">
## content ##
</div>
pagination.coffee:
jQuery ->
$('.load-more').on 'click', ->
postId = $(this).attr('id')
more_posts_url = $('#post-'+postId+' .pagination .next_page').attr('href')
if more_posts_url
$('.load-more').html('<img src="/assets/ajax-loader.gif" alt="Loading..." title="Loading..." />')
$.getScript more_posts_url
return
return
index.js.erb:
<%= #posts.each do |post| %>
$('#post-<%= post.id %>').append('<%= j render post.replies %>');
<% end %>
But this does nothing.
I really don't understand how JS works for multiple records on one page.
I suppose this could help: https://jsfiddle.net/se708oou/2/
Main points of difference:
You should loop through all of the .load-more elements
$('.load-more').each(function() {
Change reference to use this
$(this).on('click', function() {
(Miscellaneous) This is how you take data-* in jQuery:
postId = $(this).data('id');
Cheers! :)
Your posts div
<div class="post" data-id="<%= post.id %>">
...
</div>
Has a class of post and a data attribute id, but in index.js.erb you are trying to select #post-<%= post.id %>
That selector isn't in the dom, You need to change your selector to
$('.post[data-id=<%= post.id %>').append('<%= j render post.replies %>');

If you can't nest HTML forms, how can you submit multiple selections?

So for example, I have a table with a checkbox for each row. Now, I added in the functionality to be able to delete multiple selected rows by using built in rails form helper. The problem is, I also need to be able to 'disable selected' and 'enable selected' rows as well.
<%= form_tag sccm_destroy_multiple_url , method: :delete do %>
.... some table rows and data
<%= check_box_tag "ID[]", group.id %>
... some more rows
<%= button_tag "Delete Selected", type: 'button submit', class: "btn btn-danger",data: {confirm: "Are you sure you want to delete these groups?"} do %>
<i class="fa fa-trash-o"></i> Delete Selected
<%end%>
<%end%>
Now I need to put another button to "Disable Selected" but I can't do this since it would be nesting forms and forms are the only way to store multiple checkbox IDs that I'm aware of...any ideas?
Basically rails gets around this limitation in HTML by creating arrays and nested hashes from the name attributes:
<input type="text" name="dogs[0][breed]" value="Husky">
<input type="text" name="dogs[1][breed]" value="Shiba Inu">
rails will interpret these params as:
"dogs" => {
"0" => {
"breed" => "Husky"
},
"1" => {
"breed" => "Shiba Inu"
},
}
You would normally use fields_for which gives you a special "scoped" form builder instance:
<%= forms_for(#adaption_agency) do |k| %>
<%= f.fields_for(:dogs) do |doggy_fields| %>
<%= doggy_fields.text_field :breed %>
<% end %>
<% end %>
In your case what you could create an update_multiple route and use fields_for with an array of records.
But I would consider using ajax instead to allow the user to manipulate several records on the same page with just the standard CRUD actions. It is a lot less complex than trying to mosh everything into mega actions.
<%= dogs.each do |doggy| %>
<%= form_for(doggy), class: 'doggy-form' do |f| %>
<%= f.text_input :breed %>
<% end %>
<%= button_to('Delete', dog_path(doggy), method: :delete, class: 'doggy-form') %>
<% end %>
Note that this creates forms for each type of action.

Jquery/javascript flash function for multiple elements

Check out this piece of code:
var shipping = $('#shipping_cell');
var total = $('#total_cell');
flash_cell(shipping);
flash_chell(total);
function flash_cell(target){
var background = target.css('backgroundColor');
target.stop().css("background-color", "#ac4341").animate({ backgroundColor: background}, 1500);
}
When I run this code, only the #shipping cell flashes.
If I switch the lines flash_cell(shipping); and flash_cell(total); around, neither one flashes.
Why don't they both flash?
Edit - here is my html
<td id = 'total_cell'><%= view_in_preferred_currency(#order.total) %></td>
<td id = "shipping_cell">
<% if #order.free_shipping? or #order.collection? %>
<%= view_in_preferred_currency(0) %>
<% else %>
<%= view_in_preferred_currency(#order.shipping_option.price) %>
<% end %>
</td>
Fix your typo:
flash_chell(total) to flash_cell(total)

JQuery: Run script on ajax added form elements

I have a form element which is being pulled in on request with ajax. I am then trying to perform an ajax request on the inserted text box to find a location as it is typed. The code works on the first textbox but simply fails when the second one is inserted. I've tried to get the script to reload itself when the ajax has completed but it still won't work. Help would be much appreciated.
Form.html.erb - Sets up the rails nested form and pulls in partial
<%= nested_form_for(#post, :html=> {:multipart => true, :class=> "new_blog_post", :id=> "new_blog_post"}) do |f| %>
...
<fieldset>
<%= render :partial => 'search_locations', :locals => { :f => f } %>
</fieldset>
<p><%= f.link_to_add "Add a location", :locations %></p>
...
<% end %>
partial.html.erb - Pulled in on page load and then when 'Add a location' button is pressed
<fieldset>
<%= f.fields_for :locations do |m| %>
<%= m.text_field :name ,:class=>"localename", :placeholder=> "Name of the location", :autocomplete => "off" %>
<%= m.text_field :longitude, :class => "long" %>
<%= m.text_field :latitude, :class => "lat" %>
<div class="latlong">
<p class="help-block">Enter the name of the town or city visited in this blog entry.</p>
</div>
<%= m.link_to_remove "Remove this location" %>
<% end %>
</fieldset>
Javascript (placed at bottom of form)
<script type="text/javascript">
function locationchecker() {
// Rails to multiply the script 20 times
<% (0..20).each do |i| %>
// when the #search field changes
$(".localename:eq(<%=i%>)").keyup(function() {
// get the value of searchfield
var location<%=i%> = $(".localename:eq(<%=i%>)").val();
//Take the value of the textbox and pull it from geocoder
$.get('/locations/location?location='+location<%=i%>,this.value, function(searchone<%=i%>) {
$(".latlong:eq(<%=i%>)").html(searchone<%=i%>);
})
// Upon complete run the script again
.complete(function(searchone<%=i%>) { locationchecker });
});
<%end%>
}
// load script on doc ready
$(document).ready(locationchecker);
</script>
Help would be great!
Thanks in advance,
James
you should use the .on()(jQuery api doc) method to attach your keyup event handler, like so :
$('#myForm').on('keyup','.localename',function() {
// stuff here
var location = $(this).val(); // this = element on which the event was triggered
});

Categories