refresh page once checkbox is checked (in the background) - javascript

How can I refresh the page (in the background, seamlessly) when a user checks a checkbox so that once the checkbox is checked off, that div or task is then moved to another location because it's completed?
I have separated them like so
def home
if current_user
#todos = current_user.todos.where(completed: false)
end
end
def complete
if current_user
#todos = current_user.todos.where(completed: !false)
end
end
So that once the checkbox is checked it is moved, and this works - but the page has to be refreshed to see that the task has been moved.
In my todos controller where I mark the task complete it looks like this
def completed
if #todo.update_attribute(:completed, !#todo.completed)
flash[:success] = "Congratulations, it was successful."
redirect_to dashboard_path
else
flash.now[:error] = "ERROR: Please try again."
render :new
end
end
And my view is as so
<% #todos.each do |todo| %>
<div class="card hoverable">
<div class ="card-content mh-100">
<span class="card-title"><%= todo.title %></span>
<p><%= todo.item %></p>
</div>
<div class="card-action grey lighten-5">
<p style="margin: 0;">
<%= check_box_tag 'todo[completed]', todo.id, todo.completed, data: { remote: true, url: url_for(controller: :todos, action: :completed, id: todo), method: "POST" }, id: todo.id, :onclick => "Materialize.toast('Todo Completed, Grats!', 4000)" %>
<%= label_tag todo.id, "COMPLETE", :class => 'strikethrough' %>
</p>
</div>
</div>
<% end %>
But how can I refresh the page, or the div when the checkbox is checked so the task disappears seamlessly?

Give your div a unique ID based on the todo id value so that you can select it for removal:
<div class="card hoverable" id="todo_container_<%= todo.id %>">
Add a class to your check box so that you can specify a click handler:
check_box_tag 'todo[completed]', todo.id, todo.completed, class: 'todo_completed', data: { remote: true, url: url_for(controller: :todos, action: :completed, id: todo), method: "POST" }, id: todo.id, :onclick => "Materialize.toast('Todo Completed, Grats!', 4000)"
Then (assuming you are using jQuery) specify the click handler:
$(".todo_completed").click(function(){
// it looks like you've got all the info you need for your ajax call in the data attributes attached to the checkbox, so I think the call just looks like this:
$.ajax($(this).data());
});
Finally your controller needs to render a .js template instead of redirecting - just call it completed.js.erb and it should be rendered automatically. In that template put the javascript to remove the container div from the DOM:
// completed.js.erb
$("todo_container_<%= #todo.id %>").remove();

Use removeChild() with the div id to remove it, just put this in an onClick handler for the checkbox.
If desired:
Save the div when you delete it (from the return value of removeChild) in a variable, so if the checkbox is unchecked, you can use the div in createChild().

Related

Following Or Unfollowing a User using Ajax causes href for other links to change? Images / Examples attached

I'll try explain this strange situation as best as possible. Images / Examples are attached
I have a page dedicated to show all the users a particular user is following.
users_controller.rb
def following
#pals = current_user.following
end
following.html.erb
<% #pals.each do |pal| %>
<div class="following-user-btn">
<% if current_user_is_following(current_user.id, pal.wall.id) %>
<%= link_to 'Following' , unfollow_wall_path(pal.wall.id), remote: true, method: :post, class: 'unfollow-button' %>
<% else %>
<%= link_to 'Follow' , follow_wall_path(pal.wall.id), remote: true, method: :post, class: 'btn follow-button' %>
<% end %>
</div>
<% end %>
When I load the page, everything shows up fine, the Following button is next to each user accordingly and unfollowing a user works fine. However after clicking the unfollow button once it will change the href for the other users to the first user you unfollowed. You will not be able to Follow again if the following button is currently being used by another user.
Here is my relationships controller and my javascript
def follow_wall
if current_user.follow #wall.id
respond_to do |format|
format.html { redirect_to root_url }
format.js { render 'walls/follow_wall' }
end
end
end
def unfollow_wall
if current_user.unfollow #wall.id
respond_to do |format|
format.html { redirect_to root_url }
format.js { render 'walls/unfollow_wall' }
end
end
end
Unfollow_wall.js.erb
$('.unfollow-button').bind('ajax:success', function(){
$(this).closest('.unfollow-button').hide();
$(this).closest('.following-user-btn').html('<%= link_to 'Follow' , follow_wall_path(#wall.id), remote: true, method: :post, class: 'btn follow-button' %>');
});
Follow_wall.js.erb
$('.follow-button').bind('ajax:success', function(){
$(this).closest('.follow-button').hide();
$(this).closest('.following-user-btn').html('<%= link_to 'Following' , unfollow_wall_path(#wall.id), remote: true, method: :post, class: 'unfollow-button' %>');
});
I even tried changing it to this:
$('#follow-button').attr('class', 'btn unfollow-button')
.text('Following')
.attr('href', "/<%= #wall.id %>/unfollow_wall")
.attr('id', 'unfollow-button');
$('#unfollow-button').text('Follow')
.attr('class', 'btn follow-button')
.attr('href', "/<%= #wall.id %>/follow_wall")
.attr('id', 'follow-button');
No luck for either
Notice the href is correct for all users upon a fresh reload.
When I unfollow the user in the middle, everything is still fine.
Now when I Unfollow the top user the top user href changes to the middle user? This is where I'm really getting confused?
This has been doing my head in for the past few days... ANY help is REALLY appreciated. Thank you!
I don't think you should be binding an ajax:success event at that point in the code.
Binding an event with a function to an element means that, from that time on, the element will watch for the event and react to it by running the function whenever the event happens. This means that the binding should be done before the expected time of the first event.
However Rails will run the JS in unfollow_wall.js.erb as a response to the button being clicked - that's not a time for binding the function with an event, that's a time for running the function.
The way I would do this is to not do binding, but to use the wall id in the element identifiers on the page like this:
Here see the id of the outer div of each button
<%# following.html.erb %>
<% #pals.each do |pal| %>
<div id="following-user-btn-<%= pal.wall.id %>">
<% if current_user_is_following(current_user.id, pal.wall.id) %>
<%= link_to 'Following' , unfollow_wall_path(pal.wall.id), remote: true, method: :post, class: 'unfollow-button' %>
<% else %>
<%= link_to 'Follow' , follow_wall_path(pal.wall.id), remote: true, method: :post, class: 'btn follow-button' %>
<% end %>
</div>
<% end %>
and in the js just find the button with the right id in the outer div
# unfollow_wall.js.erb
$('#following-user-btn-<%= #wall.id %>').find('.unfollow-button').hide();
$('#following-user-btn-<%= #wall.id %>').html('<%= link_to 'Follow' , follow_wall_path(#wall.id), remote: true, method: :post, class: 'btn follow-button' %>');
the js code in the unfollow_wall.js.erb file is just as it is here in entirety, not enclosed in a bind function.
The same would apply to the other js file of course.

Rails: Delete nested attribute while updating entry

I have a form with nested attributes, where you can dynamically add and remove attributes (the form lets you click "add hobby" and "remove hobby" links...a user has hobbies, and when entering his profile he can add one, two, five, or fifty hobbies).
With the help of the nested form gem this works completely fine. However, I also provide the ability to UPDATE a user's profile.
When doing this, a user can click the dynamic "remove" link to take off a hobby. However, this doesn't delete the "hobby" from the database, like I want it to. So I'm trying to write Jquery or Javascript or something that deletes the object from the database, if it exists.
This is what the code looks like:
...
...
<%= f.fields_for :hobbys, :wrapper => false do |hobby| %>
<tr class="fields">
<td> <%= user.text_field :hobby %> </td>
<td> <%= user.link_to_remove "Remove" %> </td>
</tr>
<% end %>
</table>
<p><%= f.link_to_add "Add hobby", :hobbys, :data => { :target => "#hobbys" } %></p>
<script>
$(document).on('nested:fieldRemoved', function(event){
var field = event.field;
/* ??? Delete field somehow ??? */
})
</script>
Is there any way to do this? I really don't know how to go about it....it doesn't seem like Jquery can delete off a database...
UPDATE
here's my best attempt so far...
...
...
<%= f.fields_for :hobbys, :wrapper => false do |hobby| %>
<tr class="fields">
<td> <%= user.text_field :hobby %> </td>
<td> <%= user.link_to_remove "Remove" %> </td>
</tr>
<% end %>
</table>
<p><%= f.link_to_add "Add hobby", :hobbys, :data => { :target => "#hobbys" } %></p>
<script>
$(document).on('nested:fieldRemoved', function(event){
$.get("delete", { id: 2 })
alert( "Deleted: ");
})
</script>
I'm just trying to get this damn thing to work, by hardcoding an id as the argument (since I can't yet easily extract it). But it keeps using the string "delete" as the id of the user.....huh??
Here's the log output:
Started GET "/users/delete?id=2" for 127.0.0.1 at 2016-10-05 08:35:15 -0400
Processing by UsersController#show as */*
Parameters: {"id"=>"delete"}
Current user: anonymous
Completed 404 Not Found in 19.5ms
ActiveRecord::RecordNotFound (Couldn't find User with id=delete):
You could use Jquery to call a function in Ruby to do it for you:
Javascript:
$.get( "delete", { id: id_to_delete } )
.done(function( deleted ) {
alert( "Deleted: " + deleted.id );
});
Route (route.rb):
get 'delete', to: 'application_controller#delete'
Application Controller (application_controller.rb):
def delete
id = params[:id].to_i
to_delete = Hobby.find(id).destroy
render json: {id: id}
end
Add a listener on click of the remove button for each activity and make an ajax request to your backend api which handles it. It will look something like below:
$('.activities').each(function(activity) {
$(activity).click(function(event) {
$.ajax
url: 'activity/:id',
method: delete,
success: function(data) { REMOVE ELEMENT IN HERE }
error: alert('this didnt work');
})
})

Why are all of these links to a helper method visited on each page load?

I have a view such as:
<% for i in 1..5 %>
<p>
<div style="float: left; width: auto;">
<%= button_to(i.to_s, rate(#item.id, i, item_path), method: :get, remote: true) %>
</div>
</p>
<% end %>
This creates five buttons that link to this helper function:
module UsersHelper
def rate(itemid, rating, url)
#rating = Rating.new
#rating.userid = current_user.id
#rating.itemid = itemid
#rating.rating = rating
#rating.save
url
end
end
However, every time I load the page, the rate method is called five times for every rating from 1 to 5. Thus, it doesn't call the rate method when I click one of these buttons.
Why are all of these links to a helper method visited on each page load?
What I want is to call the rate method only when I click a button. How can I fix this for such a behavior?
Why all of these links to a helper method are visited on each page load?:
First thing's first, the view code is evaluated before rendering of the page on the client(browser). Hence, the loop and the ruby code within the loop is also being called/evaluated before the page is rendered on your browser. That's why rate method is being called for each value of i in your for loop.
Second, view helpers are for view layer logic(s), not for saving an active record object. Because each time you hit this page, you'll end up having ratings saved for that item from 1 to 5 in your db.
Solution:
You can create an another method in your ItemsController, let's call it rate:
def rate
#item = Item.find(params[:id])
#rating = #item.ratings.build(rating: params[:rating], userid: current_user.id)
respond_to do |format|
if #rating.save
format.js { }
else
format.js {render partial: 'errors', status: :unprocessable_entity }
end
end
end
In your routes.rb:
get '/items/:id/rating/:rating' => 'items#rate', as: :rate_item
In your view file:
<% for i in 1..5 %>
<p>
<div style="float: left; width: auto;">
<%= button_to(i.to_s, rate_item_path(#item, i)), method: :get, remote: true) %>
</div>
</p>
<% end %>

Rails, Ajax, and boolean; can't uncheck box

I know there are a bunch of related questions out there, but I can't get mine to work. Here is what I have...
#app/views/tasks/index.html.erb
<%- #tasks.each do |task| %>
<div class="task-wrapper">
<%= check_box_tag 'checked_in', task.id , task.checked_in, :class => "task-check" %>
<%= content_tag :span, task.name %>
</div>
<% end %>
<%= link_to 'New Task', new_task_path %>
<script>
$(".task-check").bind('change', function(){
if (this.checked){
$.ajax({
url: '/tasks/'+this.value+'/toggle',
type: 'POST',
data: {"checked_in": this.checked}
});
}
else {
alert("no");
}
});
</script>
#app/controllers/tasks_controller.rb
...
def toggle
#task = Task.find(params[:id])
if #task.update_attributes(:checked_in => params[:checked_in])
# do I need something here?
else
# do I need something here?
end
end
...
My task model has a 'checked_in' attribute that is boolean.
I got this code from this question...
Rails change boolean value with checkbox and jquery ajax
...and don't quite understand everything that is going on. When I create a new task I can successfully check the box to set my boolean value to true. However, when I uncheck the box I get the js pop-up that says "No", but nothing get set in the DB, and nothing is sent back to server.
Any ideas?
The problem comes from your js code
$(".task-check").bind('change', function(){
if (this.checked){
$.ajax({
url: '/tasks/'+this.value+'/toggle',
type: 'POST',
data: {"checked_in": this.checked}
});
}
else {
alert("no");
}
});
When you check/uncheck the box, the changeevent is triggered, then the function is testing this.checked. It returns false false when the box is unchecked, so you don't go inside the condition but directly in the else, which calls alert.
So you probably want to remove the condition.
Thats how browsers work. They dont send the value of unchecked checkboxes.
Check/Uncheck need to be determined based on the presence of the parameter.
Thanks Antoine. That worked...doing the best I can to learn JS. For posterity here is what worked...
app/views/tasks/index.html.erb
<%- #tasks.each do |task| %>
<div class="task-wrapper">
<%= check_box_tag 'checked_in', task.id , task.checked_in, :class => "task-check" %>
<%= content_tag :span, task.name %>
</div>
<% end %>
<%= link_to 'New Task', new_task_path %>
<script>
$(".task-check").bind('change', function(){
$.ajax({
url: '/tasks/'+this.value+'/toggle',
type: 'POST',
data: {"checked_in": this.checked}
});
});
</script>
...additionally I was getting a template error being thrown in the console, so here is updated controller code.
def toggle
#task = Task.find(params[:id])
#task.update_attributes(:checked_in => params[:checked_in])
render :nothing => true
end

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