Triggering a click through Jquery on ruby code - javascript

So I'm trying to get my f.submit to be triggered when I click f.check_box. I don't know if you can use jquery to work on ruby... But basically this is a view of a to-do list with all the items on the page. When I click the checkbox to mark it off, I want it to be automatically submitted.
I thought I could assign a div tag on the f.check_box and the f.submit to trigger them... This is the first bit of JQuery I've working with.
<h1><%= #list.title %></h1>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<div>
<h2><% #list.items.each do |item| %></h2>
<%= item.content %>
<%= form_for([#list, item]) do |f| %>
<div id="target">
<%= f.check_box :complete %>
</div>
<div id="handler">
<%= f.submit %>
<% end %>
</div>
<% end %>
</div>
<script>
jQuery(document).ready(function() {
jQuery("#target").click(function() {
jQuery("#handler").click();
});
});
</script>
<% if policy(#list).update? %>
<%= link_to "Edit List", edit_list_path, class: 'btn btn-success' %>
<% end %>
<div class="col-md-4">
<% if policy(Item.new).create? %>
<%= link_to "New Item", new_list_item_path(#list), class: 'btn btn-success' %>
<% end %>
<% if policy(#list).destroy? %>
<%= link_to "Delete List", #list, method: :delete, class: 'btn btn-danger', data: { confirm: 'Are you sure you want to destroy this lovely list?'} %>
<% end %>
</div>
</div>
<%= render "items/form" %>
<!--
new_list_item_path
/lists/5/items/new
-->

div does not fire onclick event you need to set onchange method of checkbox which will submit the form.
Here is a code for that.
You need to set different id for every submit-button and then you can submit that form using Jquery.
I set the onchange method of checkbox which submits that forms according to item id.
<h1><%= #list.title %></h1>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<div>
<%index=0%>
<h2><% #list.items.each do |item| %></h2>
<%= item.content %>
<%= form_for([#list, item]) do |f| %>
<%=f.check_box :complete,{:onchange=> "submit_form("+#list.items[index].id.to_s+");"}%>
<%= f.submit :id=>#list.items[index].id%>
<%index+=1%>
<% end %>
<% end %>
</div>
<% if policy(#list).update? %>
<%= link_to "Edit List", edit_list_path, class: 'btn btn-success' %>
<% end %>
<div class="col-md-4">
<% if policy(Item.new).create? %>
<%= link_to "New Item", new_list_item_path(#list), class: 'btn btn-success' %>
<% end %>
<% if policy(#list).destroy? %>
<%= link_to "Delete List", #list, method: :delete, class: 'btn btn-danger', data: { confirm: 'Are you sure you want to destroy this lovely list?'} %>
<% end %>
</div>
</div>
<%= render "items/form" %>
<script>
function submit_form(id) {
$('#'+id).click();
}
</script>

Um, try something like:
$("input[type=checked]").on("click", function() {
if( $(this).is(':checked') ) { $('form').submit() }
}
And you might want to
<%= f.check_box :complete, html: { class: "check_complete"} %>
and
<%= f.submit, ".." id: "handler"%>
And then replace replace the input[type=checked] with .check_complete and maybe use the ("#handler").click(); instead of .submit()

Related

How to use Ajax to show first and only one comment as soon as it is created

At present my application is able to append comments to microposts that already have comments. Below is _micropost.html.erb (simplified):
<li id="micropost-<%= micropost.id %>">
<span class="content">
<%= micropost.content %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
~ <%= link_to "Comment", "#", class: "comment-link", remote: true %>
<% if micropost.comments.any? %>
~ <%= link_to "Show/hide comments", "#", class: "comments-link", remote: true %>
<% end %>
</span>
<% if logged_in? && (current_user == micropost.user || current_user.friend?(micropost.user)) %>
<div class="comment-section">
<%= form_for(current_user.comments.build, remote: true) do |f| %>
<%= f.hidden_field :micropost_id, value: micropost.id %>
<%= f.text_area :content, rows: "1", class: "comment_area" %>
<%= f.submit "Comment", class: "btn btn-primary btn-sm" %>
<% end %>
</div>
<% end %>
<div class="comments-section">
<% if micropost.comments.any? %>
<ol id="comments_micropost-<%= micropost.id %>">
<% micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
</div>
</li>
create.js.erb is:
var comments = $('ol#comments_micropost-<%= #micropost.id %>');
comments.append('<%= escape_javascript(render partial: #comment) %>');
As it is conceived, create.js.erb implies that the comment created is added to other comments, that is that the comment created is not the first one. In this case, var comments is not null and the last line of code append the comment to the list of the other comments.
Also, in case micropost.comments is not nil, the user can use the "Show/hide comments" link to toggle the order list with id="comments_micropost-<%= micropost.id %>"
The problem with this configuration is that in case a user add to any micropost the first comment (that is the user writes his comment when micropost.comments == 0) there is no chance to see the result without refreshing the page.
So I am asking: how can I edit create.js.erb so that the user can see straight away the result of posting the first comment and that the "Show/hide comments" link be added to the page?
I tried the following code but it does not work:
if (comments !== null) {
comments.append('<%= escape_javascript(render partial: #comment) %>');
} else {
$('#micropost-<%= #micropost.id %>').find('.comments-section').append("<ol id='comments_micropost-<%= #micropost.id %>'><%= escape_javascript(render partial: #comment) %></ol>");
$('#micropost-<%= #micropost.id %>').find('.timestamp').append(" ~ <%= link_to 'Show/hide comments', '#', class: 'comments-link', remote: true %>");
};
<li id="micropost-<%= micropost.id %>">
<span class="content">
<%= micropost.content %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
~ <%= link_to "Comment", "#", class: "comment-link", remote: true %>
<% if micropost.comments.any? %>
~ <%= link_to "Show/hide comments", "#", class: "comments-link", remote: true %>
<% end %>
</span>
<% if logged_in? && (current_user == micropost.user || current_user.friend?(micropost.user)) %>
<div class="comment-section">
<%= form_for(current_user.comments.build, remote: true) do |f| %>
<%= f.hidden_field :micropost_id, value: micropost.id %>
<%= f.text_area :content, rows: "1", class: "comment_area" %>
<%= f.submit "Comment", class: "btn btn-primary btn-sm" %>
<% end %>
</div>
<% end %>
<div class="comments-section">
<%= render partial: comments, micropost: micropost %>
</div>
</li>
And in _comments.html.erb
<% if micropost.comments.any? %>
<ol id="comments_micropost-<%= micropost.id %>">
<% micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
And in create.js.erb
var comments = $('ol#comments_micropost-<%= #micropost.id %>');
if (comments == undefined) {
$('div#comments-section').html('<%= escape_javascript(render partial: comments, micropost: #micropost) %>');
}
else {
comments.append('<%= escape_javascript(render partial: #comment) %>');
};
I solved my issue creating as originally suggested by Minu a app/views/comments/_comments.html.erb file as follows:
<% if #micropost.comments.any? %>
<ol id="comments_micropost-<%= #micropost.id %>">
<% #micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
Without changing partial _micropost.html.erb I edited create.js.erb as follows:
var comments = $('ol#comments_micropost-<%= #micropost.id %>');
if (comments.length == 0) {
$('#micropost-<%= #micropost.id %>').find('.comments-section').html("<%= escape_javascript(render partial: 'comments/comments') %>");
}
else {
comments.append('<%= escape_javascript(render partial: #comment) %>');
};
When micropost.comments.any? is false, var comments is neither null or undefined, but is considered as an empty array, as can be verified by using a web browser console. Hence the use of if (comments.length == 0). See post at Stackoverflow.

Form select option to change what gets rendered

Ruby on Rails 4 form with a drop down selection. If Multiple Choice is selected I want to render a page. If True/False is selected I want to render a different page.
I do not know why this isn't working, My javascript knowledge is bad:
<h1>New question</h1>
<%= form_for(#question) do |f| %>
<%= render 'shared/error_questions' %>
<%= render 'form', f: f %>
<%= f.fields_for :answers do |builder| %>
<div id="mcanswers" style="display:none">
<h1>Answers</h1>
<%= render 'four_answers', :f => builder %>
<%= f.submit "Create Question", class: "btn btn-lg btn-primary" %>
</div>
<div id="tfanswers" style="display:none">
<h1>Answers</h1>
<%= render 'tf_answers', :f => builder %>
<%= f.submit "Create Question", class: "btn btn-lg btn-primary" %>
</div>
<% end %>
<% end %>
<hr />
<%= link_to 'Back', questions_path %>
<script>
function checkType() {
if ($('#question_question_type').val('MC'))
{
$('#mcanswers').css('display', 'block');
}
else if ($('#question_question_type').val('TF'))
{
$('#tfanswers').css('display', 'block');
}
}
$(document).ready(function() {
$('select#question_question_type').on('change', function() {
checkType();
});
});
</script>
Everything is rendered from the beginning. The div is just hiding it. I had to use controller logic to decide when to render.

Button doesn't update in Ajax on Users Index page - Rails Tutorial 4

TLDR: Trying to add a follow/unfollow button to the Users#Index action but when clicking on the button nothing happens.
I have followed Michael Hartl's Rails Tutorial app and now that it's complete I want to add extra functionality for the Follow/Unfollow button. Currently, you can only follow/unfollow a user after visiting their profile page thru the Users Show action. I've attempted to expand this functionality to the Index page of the Users controller so that instead of having to visit each user's profile page in order to follow/unfollow them, a follow button will also appear next to their name in the Index view.
The code that works initially for the follow/unfollow button on the Users Show action:
users_controller.rb
https://gist.github.com/anonymous/9602598
show.htlm.erb for users view
https://gist.github.com/anonymous/9602616
_follow_form.htlm.erb partial for users view
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
_follow.html.erb partial for users view
<%= form_for(current_user.relationships.build(followed_id: #user.id),
remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
_unfollow.html.erb partial for users view
<%= form_for(current_user.relationships.find_by(followed_id: #user.id),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
create.js.erb inside of my relationships view
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= #user.followers.count %>')
destroy.js.erb inside of my relationships view
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= #user.followers.count %>')
index.html.erb inside of the users view
<%= render #users %>
_user.html.erb partial inside of users view
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
I've tried a few different approaches that so far have been fruitless
First I tried simply rendering the follow_form partial inside of the _user partial just like it's done for the User Show view
_user.html.erb partial inside of users view
<%= render 'follow_form' if signed_in? %>
this resulted in the following error: NoMethodError in Users#index "undefined method `id' for nil:NilClass" and it hilights the following line of code inside of the follow_form partial
<% if current_user.following?(#user) %>
After mucking around with the variables and the controller for a few hours I finally managed to get the buttons to show properly on the index page with the following code inside of the _user.html.erb partial
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
<% if current_user.following?(user) %>
<%= form_for(#current_user.relationships.find_by(followed_id: #users),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
<% else %>
<%= form_for(current_user.relationships.build(followed_id: #users),
remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
</li>
This code however, only shows the correct follow/unfollow buttons for each user but when you click a button nothing happens. I also attempted to edit the JS files with the following code
create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#user").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= #user.followers.count %>')
destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#user").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= #user.followers.count %>')
This didn't have any effect.
The more I tinker with different parts of the code the more it's confusing me. Here is my relationships controller for good measure.
relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :signed_in_user
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
end
I know it's alot but if anyone can help shed some light on my situation I would be very grateful. This is my first venture outside of tutorials and I figured it would be a good idea to try and add features to an already working project instead of start something from scratch.
Just in case anybody was on this question and was still looking for the correct Ajax code. This works with the existing controller and nothing else will have to be changed.
create.js.erb
var indexed_form = "follow_form_<%=#user.id%>"
if ( document.getElementById(indexed_form) ){
var jquery_indexed_form = "#" + indexed_form
$(jquery_indexed_form).html("<%= escape_javascript(render('users/unfollow')) %>");
}
else {
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= #user.followers.count %>');
}
destory.js.erb
var indexed_form = "follow_form_<%=#user.id%>"
if ( document.getElementById(indexed_form) ){
var jquery_indexed_form = "#" + indexed_form
$(jquery_indexed_form).html("<%= escape_javascript(render('users/follow')) %>");
}
else {
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= #user.followers.count %>');
}
_user.html.erb
<div class="col-md-2">
<% unless current_user?(user) %>
<% form_id = user.id.to_s %>
<div id="follow_form_<%= form_id %>">
<% if current_user.following?(user) %>
<%= form_for(current_user.active_relationships.find_by(followed_id: user.id),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn" %>
<% end %>
<% else %>
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
<% end %>
</div>
<% end %>
</div>
This is my first post. Yay! Hope it helps someone!
Use the following code in _user.html.erb partial:
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
<% if current_user.following?(user) %>
<%= form_for(current_user.relationships.find_by(followed_id: user.id),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
<% else %>
<%= form_for(current_user.relationships.build(followed_id: user.id),
remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
</li>
I made couple of changes to the code in form_for method call in 2 places:
#current_user should be current_user.
Secondly, followed_id: #users should be followed_id: user.id

How can I specify which container when the elements are generated in a loop?

I am displaying a list of messages group by sender.
I'm also displaying a form after each group of messages so that I can reply to that particular sender.
<% #grouped_messages.each do |sender, messages| %>
<% messages.each do |msg| %>
<p><%= msg.content %></p>
<% end %>
<div class="reply-container", id='reply-container'>
<%= form_for #message do |f| %>
<%= f.text_field :content %>
<%= f.submit "Reply" %>
<% end %>
</div>
<%= link_to "Reply", '#', class: 'reply-link', id: 'reply-link' %>
<% end %>
I want to be able to show the form only when the 'Reply' link is clicked.
$(".reply-link").click(function(e){
e.preventDefault();
$('#reply-container').toggle();
$('#reply-link').toggle();
});
This doesn't work as there can only be one id on the page and all the reply-container's have the same id.
How can I specify which container to hide when the elements are dynamically generated in a loop?
you can try something like:
$(".reply-link").click(function(e){
e.preventDefault();
$(this).closest( '.reply-container').toggle();
$(this).toggle();
});
and you can remove ids: "reply-link" and "reply-container"
edit:
but you can make it better:
<div class="reply-container", id="reply-sender-#{sender.id}-container">
<%= form_for #message do |f| %>
<%= f.text_field :content %>
<%= f.submit "Reply" %>
<% end %>
</div>
<%= link_to "Reply", '#', class: 'reply-link', id: "reply-sender-#{sender.id}" %>
and then it could look like:
$(".reply-link").click(function(e){
e.preventDefault();
$("#" + $(this).attr("id") + "-container").toggle();
$(this).toggle();
});
$(".reply-link").click(function(e){
e.preventDefault();
$(this).siblings('.reply-container').toggle();
$(this).toggle();
});
Edit:
You should also separate groups into divs:
<% #grouped_messages.each do |sender, messages| %>
<div class='message_group'>
<% messages.each do |msg| %>
<p><%= msg.content %></p>
<% end %>
<div class="reply-container", id='reply-container'>
<%= form_for #message do |f| %>
<%= f.text_field :content %>
<%= f.submit "Reply" %>
<% end %>
</div>
<%= link_to "Reply", '#', class: 'reply-link', id: 'reply-link' %>
</div>
<% end %>

How do I apply function to just the class a jquery ajax submission was done from?

Here is the code I'm currently using:
$.ajax({
success: function(){
$('.post_container').append('test <br />');
}
});
<% sleep 1 %>
It is similar to the code I used for my single main micropost form but with this there are several comments that use the same class and so test is being applied to all post_containers rather than the one the post was just made to. "test" text will eventually be replaced with the div that holds the actual comments users post.
Normally I would use "this" but that won't work here.
HTML:
<div class="post_content">
<div class="post_container">
<div class="userNameFontStyle">
<%= link_to current_users_username.capitalize, current_users_username %> -
<div class="post_time">
<%= time_ago_in_words(m.created_at) %> ago.
</div>
</div>
<%= simple_format h(m.content) %>
</div>
<% if m.comments.any? %>
<% comments(m.id).each do |comment| %>
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(comment), :class => "commenter_photo"), commenter(comment.user_id).username %>
<div class="commenter_content">
<div class="userNameFontStyle">
<%= link_to commenter(comment.user_id).username.capitalize, commenter(comment.user_id).username %> - <%= simple_format h(comment.content) %>
</div>
</div>
<div class="comment_post_time">
<%= time_ago_in_words(comment.created_at) %> ago.
</div>
</div>
<% end %>
<% end %>
<% if logged_in? %>
<%= form_for #comment, :remote => true do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :micropost_id, :value => m.id %>
<%= f.text_area :content, :placeholder => 'Post a comment...', :class => "comment_box", :rows => 0, :columns => 0 %>
<div class="commentButtons">
<%= f.submit 'Post it', :class => "commentButton" %>
<div class="cancelButton">
Cancel
</div>
</div>
<% end %>
<% end %>
</div>
</div>
How would I deal with this?
Kind regards
NEW:
$(function() {
$('.post-form').submit(function(){
var $post_content = $(this).find('.post_content');
$.ajax({
url: this.attributes['action'],
data: $(this).serialize(),
success: function() {
$post_content.append('test <br />');
}
})
return false; //this will stop the form from really submitting.
});
});
This should do what you're looking for. Simply include this javascript anywhere.
OLD:
$('form').submit(function(){
$.ajax({
url: this.attributes['action'],
data: $(this).serialize(),
//the below line might need to be adapted.
var post_content = $(this).find('.post_content');
success: function() {
$(post_content).append('test <br />');
}
})
this assumes that there is only one form on the page. However, for the code to completely work, I need to know how to differentiate which .post_content is the "submitted" post_content. How do you programatically determine that? Is there a different button for each post_content? Or are there different forms around each post_content div? Whichever way it is, you'll have to include that somehow into the js code.
This is how I had to do it in the end.
.new_comment is my form id
$('.new_comment').on('ajax:success', function(){
$(this).parent('.post_content').find('.comment_container:last').after("<BR />TEST <BR />");
});
<% sleep 1 %>
The only issue now is identifying the actual comment_container for the post just made.

Categories

Resources