From file soul.html.erb , partial view called at the time of page load
<%= render 'contact_options_soul_d' %>
In file contact_options_soul_d.html.erb partial view looks like this -
<div id="contact-option">
<div id= 'un-authenticated' data-access-api-result = <%= #valid_ticket %> %></div>
</div>
On click of a button a Rest call happens in controller and partial view is called from partial_create.js.erb
def partial_create
respond_to do |format|
format.js
end
return
end
File partial_create.js.erb
$('#contact-option').html('<%= escape_javascript(render :partial => 'rhythm/contact_options_soul_d') %>')
My Question is - partial view is called , breakpoint hits and new value of #valid_ticket also gets updated, but view is not getting updated as webpage still looks same even after updation.(View remains same when checked in browser inspect)
Please help!!!
This is not an answer to exactly the way you're doing it, but you could always render it in the controller and return that on "respond_to", then on Ajax success use the returned value to substitute the html:
def partial_create
html = (render_to_string partial: 'rhythm/contact_options_soul_d', locals: { if_you_need: variables_in_partial })
respond_to do |format|
format.json { render json: { new_html: html, success: true } }
end
return
end
then on your JS code (this with jQuery):
function soul_searching(parameters) {
$.ajax({
url: "YOUR/POST/ROUTE",
type: "POST",
dataType: "json",
data: {
any_parameters: 'you_need_to_pass_to_controller'
},
success: function(data) {
$('#contact-option').html(data['new_html']);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
//DO SOMETHING
}
});
}
You need to prepend partials with an underscore. For example:
_contact_options_soul_d.html.erb
Note: You only need to do this to the file name. You can still call the partial with
<%= render partial: 'contact_options_soul_d.html.erb' %>
Also make sure you're referencing the path if the partial is in a separate folder.
Related
I want to send some data from view to controller in rails through ajax.
I have the following code in
app/view/static/home.html.erb
<script type="text/javascript">
var dummy = "testtext";
$('#finish').click(function() {
$.ajax( {
url: '/finish',
type: 'POST',
data: dummy,
dataType: 'text'
});
});
</script>
<body>
<%= button_to "Finish", {:action => 'finish', :controller => 'static'}, :method => :post, id => 'finish' %>
</body>
in
app/view/static/finish.html.erb
<p><%= #data %></p>
app/controller/static_controller.rb
def finish
#data = params[:data]
end
in routes.rb
post 'finish' => 'static#finish'
My understanding is that on button click the ajax script will be executed and rails action will store the data passed from view. This doesn't seem to work. I'm not sure if my understanding of the flow is right.
Because you are calling params[:data] in the controller, you need to specify that {data: dummy} in the AJAX data section
<script type="text/javascript">
var dummy = "testtext";
$('#finish').click(function() {
$.ajax( {
url: '/finish',
type: 'POST',
data: {data: dummy},
dataType: 'text'
});
});
</script>
Also you might want to respond to your AJAX call in your controller using the following
def finish
#data = params[:data]
respond_to do |format|
format.json { insert_your_code_here }
end
end
I'm currently learning rails and working on what I'm sure is everyone's first rails app, a simple todo list. I need to implement a checkbox next to the items to indicate whether they are complete or not. Each item has a boolean attribute called "completed" in their model. I have found a couple checkbox questions while searching but none explain the syntax very easily in the context of the index view.
Also, I really want the checkbox to work without a submit button. I know I could accomplish something like this using AngularJS's ng-model but I don't think it would be practical to implement angular for such a small thing and I don't know how angular works with rails.
If anyone could give me a pointer in the right direction, it would be greatly appreciated. Here's my index.html.erb for reference.
<h1>
To Do List
</h1>
<table>
<tr>
<% #todo_items.each do |item| %>
<!-- Checkbox here -->
<tc style="<%= 'text-decoration: line-through' if item.completed %>">
<%= link_to item.title, item %>
</tc>
<tc>
<%= item.description %>
</tc>
<tc>
<%= link_to "Edit", edit_todo_item_path(item) %>
</tc>
<tc>
<%= link_to "Delete",item, data:{:confirm => "Are you sure you want to delete this item?"}, :method => :delete %>
</tc>
<hr/>
<% end %>
</tr>
</table>
<p>
<%= link_to "Add Item", new_todo_item_path %>
</p>
This is my way, I don't know this way is right direction or not but this works for me (also different case but same of concept).
views for checkbox
You could put an id item or something into attribute of checkbox for find an object in controller if you send data to controller for get record of object, and you could define if attribute completed of record is true or false:
<%= check_box_tag :completed_item, 1, item.completed? ? true : false, { class: 'name-of-class', data: { id: item.id} } %>
controller
You need two action call set_completed and remove_completed, and also you don't need templates for them, just use format as json:
before_action :set_item, only [:set_completed, :remove_completed, :other_action]
def set_completed
#item.set_completed!
respond_to do |format|
format.json { render :json => { :success => true } }
end
end
def remove_completed
#item.remove_completed!
respond_to do |format|
format.json { render :json => { :success => true } }
end
end
private
def set_item
#item = Item.find params[:id]
end
Model
For set_completed! and remove_completed! you could define in your model
def set_default!
self.update_attributes(:completed => true)
end
def remove_default!
self.update_attributes(:completed => false)
end
routes
resources :address do
collection do
post 'set_completed'
post 'remove_completed'
end
end
Also, you need help JavaScript for handle send request from view to controller event click of checkbox:
jQuery
$(".completed_item").click(function(){
var check = $(this).is(":checked");
if (check == true){
set_completed($(this).attr('data-id'));
} else{
remove_completed($(this).attr('data-id'));
}
});
function set_completed(data_id) {
$.ajax({
type: 'POST',
url: "/items/set_completed",
data: { id: data_id},
dataType: 'json',
success: function(response){
if(response){
}else{
alert('error');
}
}
})
}
function remove_compelted(data_id) {
$.ajax({
type: 'POST',
url: "/items/set_completed",
data: { id: data_id},
dataType: 'json',
success: function(response){
if(response){
}else{
alert('error');
}
}
})
}
Within a rails 4 app, I am using a link_to to send an upvote on posts via json.
Here is what I have in my posts controller:
def upvote
#post = Post.find(params[:id])
#post.liked_by current_user
respond_to do |format|
format.html {redirect_to :back }
format.json { render json: { count: #post.get_upvotes.size } }
end
end
Here is what I have in my view
<%= link_to like_post_path(post), method: :put, class: 'vote', remote: true, data: { type: :json } do %>
<%= image_tag('vote.png') %>
<%= content_tag :span, post.get_upvotes.size %>
<% end %>
<script>
$(document)
.on('ajax:send', '.vote', function () { $(this).addClass('loading'); })
.on('ajax:complete', '.vote', function () { $(this).removeClass('loading'); })
.on('ajax:error', '.vote', function(e, xhr, status, error) { console.log(status); console.log(error); })
.on('ajax:success', '.vote', function (e, data, status, xhr) {
$(this).find("span").html(data.count);
$(this).find("img").attr("src", '<%= asset_path 'voted.png' %>');
});
</script>
When I click on the link, the vote goes through as a JSON request, I see this in my log:
Processing by PostsController#upvote as JSON
But for some reason, my snipped of javascript is not working. Neither the counter or the icon update. How can I fix this? Does this have to do with turbolinks, does it have to do with where I am placing the javascript?
In Rails you can perform a similar task by having a JavaScript response. Add in your respond_to a format.js similar to format.html then have a view upvote.js.erb that looks like:
(function() {
var postId = "#post-<%= #post.id %>";
$(postId).find(".vote").find("span").text("<%= #post.get_upvotes.size %>");
$(postId).find(".vote").find("img").attr("src", "<%= asset_path "voted.png" %>");
})();
I changed your call to .html to .text since you're not actually setting any HTML inside the element, there is no reason to call .html.
This post also assumes there is some mechanism to identify the post the vote link belongs to (in the example the parent post element has an ID of "post-#" where # is the ID of the post object).
EDIT
Two changes I'd make if I were working on this project. First I would attach the voted.png path to the .vote element as a data attribute. data-voted-image-src="<%= asset_path "voted.png" %>". Next, I would never pass a number in the return as there is no reason to do so. When the vote is clicked you can handle everything on the front end by assuming the request is successful. Which saves all this potential nastiness. While I realize that changing from what you current have to adding the data attribute isn't a huge leap I just find it more semantic than having it in the JavaScript.
The click action on the vote link then becomes:
// Assume all posts have a class 'post'
// I'm also using 'one' because once they vote they don't need to anymore
$(".post").find(".vote").one("click", function(e) {
var count = parseInt($(this).find("span").text()),
votedSrc = $(this).data("voted-image-src");
$(this).find("img").attr("src", votedSrc);
$(this).find("span").text(count + 1);
});
Now no response from the server is necessary, and you can change your JSON response to {success: true} or something simple.
jQuery is the default rails javascript library. The default rails javascript library used to be prototype, so old tutorials/docs use it. This is what the ajax looks like with jQuery:
app/controllers/static_pages_controller.rb:
class StaticPagesController < ApplicationController
def show_link
end
def upvote
respond_to do |format|
format.json {render json: {"count" => "10"} }
end
end
end
app/views/static_pages/show_link.html:
<div>Here is an ajax link:</div>
<%= link_to(
"Click me",
'/static_pages/upvote',
'remote' => true, #Submit request with ajax, and put text/javascript on front of Accept header
data: { type: :json }) #Put application/json on front of Accept header
%>
<div>Upvotes:</div>
<div id="upvotes">3</div>
<script>
$(document).ready( function() {
$(this).ajaxSuccess( function(event, jqXHR, ajaxInfo, data) {
//var js_obj = JSON.parse(jqXHR.responseText);
//$('#upvotes').html(js_obj["count"]);
//Apparently, the fourth argument to the handler, data,
//already contains the js_obj created from parsing the
//json string contained in the response.
$('#upvotes').html(data["count"]);
});
});
</script>
config/routes.rb:
Test1::Application.routes.draw do
get 'static_pages/show_link'
get 'static_pages/upvote'
...
end
url to enter in browser:
http://localhost:3000/static_pages/show_link
See jquery docs here:
http://api.jquery.com/ajaxSuccess/
Response to comment:
You could also do the following in your controller:
def upvote
#upvotes = 2 #Set an #variable to the number of upvotes
respond_to do |format|
format.js {} #By default renders app/views/static_pages/upvote.js.erb
end
end
Then:
app/views/static_pages/upvote.js.erb:
$('#upvotes').html(<%= #upvotes %>)
I new in rails, and i can't understand how to rewrite next functionality.
For example:
I have a list of products.
And every product has some field ( category )
def index
if params[:select_query]
#posts = Post.selecting(params[:select_query])
else
#posts = Post.all
end
respond_to do |format|
format.html # index.html.erb
format.js
end
end
Index.html
<%= select_tag "credit_card", options_for_select([["first", 1], ["second", 2], ["third", 3]], 2) %>
<div class='tab'>
<%= render 'table' %>
</div>
<%= link_to 'Select', posts_path(select_query: 'first'), class: 'link', remote: true %>
Index.js.erb
$('.tab').html("<%= j render 'table' %>")
JS
$(function(){
$('#credit_card').on('change', function(){
variable = $(this).find('option:selected').text();
$('.link').attr('href', '/posts?select_query='+variable).click();
});
});
I try to realise same functionality but without additional link ( button )
In perfect way i should have only JS file ( with Ajax )
Could help me rewrite this functionality by ajax.
You could try this
$('#credit_card').on('change', function(){
var variable = $(this).find('option:selected').text();
$.ajax({
url: '/posts',
data: {select_query: variable },
dataType: 'JS'});
});
Or if you don't want the js.erb at all. You can rewrite your controller as:
# ...
respond_to do |format|
format.html # index.html.erb
format.js { render partial: 'table' }
end
And add success handler for your ajax request:
$.ajax({
url: '/posts',
data: {select_query: variable },
success: function(result) {
$('.tab').html(result);
},
dataType: 'JS'});
You could also add success: window.location.reload() to you ajax call
I'm trying to ajaxify my will_pagniate pagination in rails. I want to have the old page fade out and the new one fade in.
Here's the relevant part of my controller:
respond_to do |format|
format.html # new.html.erb
format.js {
render :update do |page|
page.replace 'page', :partial => 'cur_page'
end
}
format.xml { render :xml => #branch }
end
The aforementioned partial:
<div id="page">
<%= will_paginate %>
<div id="posts">
<%= render #posts %>
</div>
<%= will_paginate %>
</div>
And the relevant part of application.js:
document.observe("dom:loaded", function() {
// the element in which we will observe all clicks and capture
// ones originating from pagination links
var container = $(document.body)
if (container) {
var img = new Image
img.src = '/images/spinner.gif'
function createSpinner() {
return new Element('img', { src: img.src, 'class': 'spinner' })
}
container.observe('click', function(e) {
var el = e.element()
if (el.match('.pagination a')) {
el.up('.pagination').insert(createSpinner())
target = $('posts')
new Effect.fade(target, { duration: 0.3, afterFinish: function()
{
new Ajax.Request(el.href,
{
method: 'get',
onSuccess: function(){ new Effect.Appear(target, {duration:0.3})}
})
}})
e.stop()
}
})
}
})
The script seems to get killed on this line,
new Effect.fade(target, { duration: 0.3, afterFinish: function()
because I see the spinner.gif start, then no fading and the page is refreshed normally. I have got the ajax working before I tried to add Effect.Fade and Effect.Appear.
Is this the right way to go about this? Should I put the effects in the controller instead?
Here is what I did using jQuery and working well too :)
Put your will_paginate helper view call in a div
#tickets_pagination
= will_paginate #tickets
In application.js
$("#tickets_pagination .pagination a").live("click", function() {
$.get("/users/?"+this.href.split("?")[1], null, null, "script");
return false
});
The javascript above will convert the pagination links in #tickets_pagination to ajax links
In your controller as usual
def index
#tickets = Ticket.all.paginate({:page => params[:page], :per_page => 10 })
respond_to do |format|
format.js
format.html
end
end
Now finally in index.js.erb
$("#tickets_list_table").fadeOut('slow');
$("#tickets_list_table").html("<%= escape_javascript(render :partial =>'tickets/tickets_table', :locals => {:tickets => #tickets}) %>");
$("#tickets_list_table").fadeIn('slow');
Here tickets/ticket_table has a table that lists all tickets. The partial is rendered in a div #ticket_list_table
Hope this will work for you as well.
I tried putting more of the work into the javascript helpers:
respond_to do |format|
format.html # new.html.erb
format.js {
render :update do |page|
page.visual_effect :fade, 'posts', :afterFinsh => "function(){" +
page.replace 'page', :partial => 'cur_page' +
page.visual_effect(:appear, 'branches') + "}"
end
}
format.xml { render :xml => #branch }
end
Then removed this part of the javascript:
new Effect.fade(target, { duration: 0.3, afterFinish: function()
I get the effect I want, but all out of order. The request completes and the html is replaced, then the div fades out and then reappears!
Not very familiar with RoR, does it generate its own client-side JS that may possibly be battling your code?
If not, I would say the problem is somewhere in your own client-side code. For testing, get rid of the HREF attribute from the anchor tag and place the URL as a string literal in the Ajax request. If nothing happens, there is a problem with the Ajax request itself. If the page loads as expected, then the event in the original scenario is not being completely stopped.
Also, clean up your JS a bit just to be sure, line-ending semi-colons where needed.
You seem to mix up things a bit.
Either you write $('posts').fade or new Effect.fade('posts').
Secondly, i can't seem to find the afterFinish option in the documentation.
So i would suggest something along the following lines:
container.observe('click', function(e) {
var el = e.element()
if (el.match('.pagination a')) {
el.up('.pagination').insert(createSpinner())
target = $('posts')
new Effect.fade('posts', { duration: 0.3});
setTimeout("new Ajax.Request(el.href, { method: 'get',
onSuccess: function(){
new Effect.Appear('posts', {duration:0.3})
} })", 1000);
e.stop();
}
})
Hope this helps.