Rails Ajax render of partial with id - javascript

I'm creating a simple voting partial, but it doesn't update because of this:
error
NameError - undefined local variable or method `scribble' for
app/views/scribbles/vote.js.erb:1:in `_app_views_scribbles_vote_js_erb
The only voting methods work without any issues, but it just doesn't update in the view because of the error above. I guess I just need to know how to pass the scribble object into vote.js.erb ???
_vote.html.erb
<%if current_user.voted_for?(scribble)%>
<a href="" id="vote_<%=scribble.id%>" name="promote" class="votes">
<div class="scribblevote">
<i class="fa fa-cloud-upload"></i>
<%=scribble.votes.count%> <%= link_to "demote", vote_scribble_path(:id => scribble.id, :vote => false), remote: true, method: :post%>
</div></a>
<%else%>
<a href="" id="vote_<%=scribble.id%>" name="promote" class="votes">
<div class="scribblevote">
<i class="fa fa-cloud-upload"></i>
<%=scribble.votes.count%> <%= link_to "promote", vote_scribble_path(:id => scribble.id, :vote => true), remote: true, method: :post%>
</div></a>
<%end%>
vote.js.erb
$("#vote_<%=scribble.id%>").html("<%= escape_javascript( render(:partial => "scribbles/vote") ) %>");
controller method
def vote
#scribble = Scribble.find(params[:scribble_id])
#vote = params[:vote]
if #vote == "true"
#v = :up
else
#v = :down
current_user.unvote_for(#scribble)
end
current_user.vote(#scribble, :direction => #v)
respond_to do |format|
format.js{}
end
scribble/_scribbles.html.erb
<% #scribbles.each do |scribble| %>
<%= render :partial=> "scribbles/vote", :locals => {scribble: scribble}%>
<%end%>

$("#vote_<%=scribble.id%>")
vs
$("#vote_<%=#scribble.id%>")
you've set up #scribble not a local var called scribble
#scribble and scribble are not the same thing.
If you never assign a value to something called scribble - then it doesn't exist... and if you try to use in anywhere... then it will explode and tell you that it doesn't exist.
You will need to use #scribble everywhere unless you deliberately set up a local variable called scribble
eg:
<%= render :partial=> "scribbles/vote", :locals => {scribble: #scribble}%>
Note. in this code you are using the variable called #scribble and setting aup a local variable (called scribble) for the partial to use.
the partial will now have access to scribble

You can pass a local to a partial like this:
render(partial: 'path_to_partial', locals: { var_in_partial: var_in_current_scope })
So...
render(partial: 'scribbles/vote', locals: { scribble: scribble })
It'll be called scribble in the _vote partial, and we're passing in scribble from our current scope.
Alternately you could use #scribble which is defined in your controller and is available to all views/partials during your current request cycle.

Related

Append ruby partial in javascript, and pass a rails variable

Creating a chat component with ActionCable in Rails5. I learned today that render partial, even in .js.erb does supposedly doesn't work. render specifically is the issue. So now I'm trying to call a partial, and pass a ruby variable to it.
I have tried many things, currently this is how I'm trying to accomplish it:
chatbox.append(<%= j (Erubis::Eruby.new(File.read(File.join(Rails.root, 'app/views/msgs',
'_msg.html.erb'))).result(msg: #msg)) %>);
and the error is
undefined method `self_or_other' for #<Erubis::Eruby:0x007f832bbb8590>
So the partial is there, but the variable is not correct.
views/msgs/_msg.html.erb
<li class="<%= self_or_other(msg) %>">
<div class="avatar">
<%# if msg_interlocutor(msg).avatar.url(:thumb) == "thumb/missing.png" %>
<%= image_tag(msg_interlocutor(msg).avatar.url(:thumb), class: "convoPic")%>
</div>
</li>
I also tried:
chatbox.append(<%= j (Msg.new(File.read(File.join(Rails.root, 'app/views/msgs',
'_msg.html.erb'))).result(msg: #msg)) %>);
And get this error:
When assigning attributes, you must pass a hash as an argument.
Trying with render:
App.msgs = App.cable.subscriptions.create('MsgsChannel', {
received: function(data) {
var chatbox = "#chatbox_" + data.convo + " .chatboxcontent"
var id = data.convo;
var sender_id = data.user.id;
var reciever_id = data.receiver;
<%= #msg %> = data.msg
$(chatbox).append("<%= escape_javascript render(:partial => 'msgs/msg', :locals => { :msg => #msg }) %>");
chatbox.scrollTop(chatbox[0].scrollHeight);
},
renderMsg: function(data) {
console.log(data)
}
});
And error I receive:
undefined method `render' for #<#<Class:0x007fe976b5c180>:0x007fe9773ed470>
How do I properly call in a partial, pass it a ruby variable (with the msg record). Thank you!!
do you have a "messages_helper.rb" file with the following
module MessagesHelper
def self_or_other(message)
message.user == current_user ? "self" : "other"
end
def message_interlocutor(message)
message.user == message.conversation.sender ? message.conversation.sender : message.conversation.recipient
end
end
This is where it's defined.

How to pass javascript variable to rails partial view

I got a situation, there is a Javascript variable I need pass to rails partial view.
For example in test.html.erb
<script type="text/javascript">
var array = <%= raw sort_section %>
for(i = 0; i < array.length; i++) {
$('#test').append("<%= j render :partial => 'section_in_panel', :locals => {:section => raw array[i]} %>");
}
</script>
But it keep throwing syntax error, I have try many ways like
{:section => j sort_section_js[i]} %>"
{:section =>" + sort_section_js[i] + "}%>"
I need to use that because I want to call ajax to change array dynamically.
Update
So, maybe I need to write a controller
def get_new_variable
...
return new_variable
end
Then in the test.html.erb
<script>
$('test').onclick(function(event) {
//write some ajax call
//get new_variable
$('#test').empty();
$('#test').append("<%= j render :partial => 'section_in_panel', :locals => {:section => raw new_variable} %>");
});
)</script>
Is that right direction?
As Alberto Juan wrote in comment, you can't use javascript variable in ruby code.
Ruby code will be interpreted before javascript and will not know what is the i.
Update: Your update will not work either as your using new_variable you get in your javascript code.
For using partial after ajax call, follow instructions in this link
Example:
items/index.html.erb
<div class="grid">
<% #categories.each do |cat| %>
<%= link_to cat.name, fetch_items_path(:cat_id => cat.id), :remote => true %>
<% end %>
<%= render partial: 'item_grid', locals: { items: #items} %>
</div>
routes.rb
get "/fetch_items" => 'items#from_category', as: 'fetch_items'
items_controller.rb
def index
#items = Item.all
#categories = Category.all
end
def from_category
#selected = Item.where(:category_id => params[:cat_id])
respond_to do |format|
format.js
end
end
views/items/from_category.js.erb
$("#items_grid").html("<%= escape_javascript(render partial: 'items_list', locals: { items: #selected } ) %>");
You can use gem gon or simply do something like this:
<script>
MyVars[:someVar] = <%= some_value %>;
</script>
But, I recommend you to separate your backend an frontend code and use JSON for passing data to JS.

How can I update the message inside the data-confirmation attribute using Jquery?

I have a polymorphic association with Resources & Flags in my rails app. Each Resource can be Flagged by a user.
On the Resource Edit Page, an Admin can delete multiple flags associated with each Resource via Jquery. (This works fine)
I am then trying to display the total number of flags remaining in an alert message using the data-confirmation attribute before a user updates a Resource.
For Example:
<%= f.submit "Update Resource", data: { confirm: "Reminder: You have #{#flaggable.flags.count} flag alerts remaining." } %>
For some reason, my jquery updates the entire div button VS the variable inside the data-confirmation attribute.
How can I directly target the variable inside the data-confirmation attribute using Jquery?
Models
class Resource
belongs_to :district
has_many :flags, as: :flaggable, :dependent => :destroy
end
class Flag
belongs_to :flaggable, polymorphic: true
end
Resource Controller
#edit page
def edit
#district = District.find_by_abbreviation(params[:district_id])
#resource = #district.resources.find(params[:id])
#flaggable = #resource
#flags = #flaggable.flags.all
end
Views
edit.html.erb - Resource Edit Page
###Renders all flags & allows a user to delete flags via Javascript.
<div id="flags">
<%= render :partial => "flags/flag", :collection => #flags %>
</div>
###Resource Form
<div>
<%= simple_form_for ([#district, #district_resource]) do |f| %>
<div id="counter>
###How can I directly target the variable inside my alert message/data-confirm?
<%= f.submit "Update Resource", data: { confirm: "Reminder: You have #{#flaggable.flags.count} flag alerts remaining." } %>
</div>
<% end %>
</div>
_flag.html.erb (partial)
<div id="<%= dom_id(flag) %>" class="flag">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">
<%= link_to '×'.html_safe, [#flaggable, flag], method: :delete, remote: true %>
</span>
</button>
<b>Flag Alert: </b> <%= flag.message %>
</div>
destroy.js.erb
###This works and removes flags
$('#flags #<%= dom_id(#flag) %>').remove();
###This doesn't update the actual data-confirm attribute message
newFlagCount = $('#flags .flag').size();
$("#counter input[data-confirm]").data("Reminder: You have #{#flaggable.flags.count} flag alerts remaining.");
Well, $("#counter") is selecting the <div id="counter"> div and .html() is changing the entire div content. So, your code is doing exactly what you are asking it to do. You should target the submit button inside your "counter" div and change the data-confirm attribute's text.
$("#counter input[data-confirm]").data("Reminder: You have #{#flaggable.flags.count} flag alerts remaining.");
Please note, that if you are changing the number of flags using javascript, the variable in the text will be the original value (#flaggable.flags.count). You would need to regex the digit in your attribute text and change it using javascript.
put your JSON into a variable, then assign it into the element attribute:
var data = { confirm: "Reminder: You have #{#flaggable.flags.count} flag alerts remaining." }
$("#counter input").attr("data-confirm",data.confirm);
Combined the answer below to solve the problem. Thanks everyone.
newFlagCount = $('#flags .flag').length;
var data = { confirm: "Reminder: You have " + newFlagCount + " flag alerts remaining." }
$("#counter input[data-confirm]").data('confirm', data.confirm)

ajax controlling in rails

Hey guys I need to know the answers to some questions. First of all how do I handle ajax call when I am not returning anything from the controller because it always ask me for the view for the called function but since I have called that function using ajax how can it have a view.(I am using it in ROR(ruby on rails))
bookmark.html.erb
<div class="row">
<div id="page-wrapper-lbms" class="small-12 medium-12 large-12 columns dashboard-page">
<input type="hidden" id="bookmarked_against_req_id" value=<%= #data2%> />
<%
if #requests != nil
#requests.each.with_index do |request,index|
if request != nil
%>
<header>
<div style="text-align:center">
</span>
</div>
<h2 style="text-align:center"><%= request.title %></h2>
<div style="text-align:center">
<h6 style="color:#aaaaaa"><strong><%= request.is_service%></strong></h6>
</div>
</header>
<div class ="row">
<div class="small-12 medium-12 large-8 columns">
<div id="request-content-lbms" class="panel">
<p>
<%= request.description%>
</p>
</div>
<div id="list-request-cat-lbms">
<span class="fa fa-tag"></span>
<% if #tag[index] != nil
#tag[index].each do |cat| %>
<%= cat.title %>
<%end%>
<%end%>
</div>
</div>
<aside class="small-12 medium-12 large-4 columns" style="padding-left:10%">
<h3 ><strong>Syed Muhammad Ali Gardezi</strong></h3>
<time><%= request.created_at %></time><br />
<%end%>
<button class="button tiny">Schedule Meeting</button>
</aside>
</div>
</div>
<%end%>
<%end%>
<script>
function ajax_bookmark(abc , cde){
var cde = $('#bookmarked_against_req_id').val();
$.ajax({
type: "GET",
url: 'bookmark_request',
data: {
d:abc,
d1:cde
},
error:function(){
},
dataType: 'json',
//beforeSend:function(){},
//complete:function(o,s){},
success:function(data){
location.href ="/requests/bookmark"
},
type: 'get'
});
}
</script
bookmark_request
def bookmark_request()
data = params[:d]
data1 = params[:d1]
data2 = data1#["$oid"]#.split('"' , 6)
#asd
request_bookmarked = Request.getRequest(data)
bookmarked_against_Request = Request.getRequest(data2)
request_bookmarked_2 = request_bookmarked
bookmarked_against_Request_2 = bookmarked_against_Request
#asd
if bookmarked_against_Request_2[:favourites]
bookmarked_against_Request_2[:favourites] << request_bookmarked[:id]
else
bookmarked_against_Request_2[:favourites] = Array.new
bookmarked_against_Request[:favourites] = Array.new
bookmarked_against_Request_2[:favourites] << request_bookmarked[:id]
end
if request_bookmarked_2[:favourites_of]
request_bookmarked_2[:favourites_of] << bookmarked_against_Request[:id]
else
request_bookmarked_2[:favourites_of] = Array.new
request_bookmarked[:favourites_of] = Array.new
request_bookmarked_2[:favourites_of] << bookmarked_against_Request[:id]
end
request_bookmarked.update(Hash['favourites' ,request_bookmarked_2[:favourites]])
bookmarked_against_Request.update(Hash['favourites' ,bookmarked_against_Request_2[:favourites]])
#asd
bookmarks = Bookmark.where(request_id: bookmarked_against_Request[:id]).first()
#asd
b = bookmarks
if bookmarks != nil
#bookmarks.each { |bookmark| bookmark.update_attributes(corsponding_requests: request_bookmarked[:id]) }
b[:corsponding_requests] << request_bookmarked[:id]
b.update(Hash['corsponding_requests' , b[:corsponding_requests]] )
else
bookmark = Hash.new
bookmark["owner_req"] = session[:user]
bookmark["request_id"] = bookmarked_against_Request[:id]
bookmark["corsponding_requests"] = Array.new
bookmark["corsponding_requests"] << request_bookmarked[:_id]
Bookmark.createBookmark(bookmark)
end
flash[:notice] = "Request has been bookmarked successfully."
end
Now when ever I run this function i need it to go into the success function of ajax in bookmark.html.erb but the problem is it says I can't find the view. What is it that I am doinf wrong over here
Second when ever I need to return something I have read that I need to make a html helper but I can't figure out what a html helper is. and how can I return a string back to ajax function
Any help will be appreciated (I am new to AJAX)
You'll probably want to take a look at the rails guides - they're a great source of general grounding: http://guides.rubyonrails.org. For returning different responses based on the request format (ajax vs. html), see http://guides.rubyonrails.org/action_controller_overview.html#rendering-xml-and-json-data and #davidwessman's answer above.
Generally, you'll typically return JSON data from an ajax request; so, for instance, in the controller you might say
respond_to do |format|
format.js {render json: #my_ojects.to_json}
end
Note that there are several ways to render json, including the gems like rabl. If you're returning json like that, you don't need to render a rails view (unless you're using a view to build your json, like rabl does or is hinted at in davidwessman's answer with js.erb).
Hope that helps.
Gonna try to answer you :
First:
If you have a special action for your ajax call you only need:
def custom_action
end
This will render the custom_action.js.erb if called with ajax, for example a form with remote: true.
If you call one of your CRUD-actions and need to be able to respond to multiple formats:
def show
#book = Book.find(params[:id])
respond_to do |format|
format.html # will render show.html.erb
format.js # will render show.js.erb
end
end
If you put a link in your view:
link_to('Remote Ajax Call', book_path(#book), remote: true)
This link will call the method show and render as :js.
It will look for app/views/books/show.js.erb which may look something like:
<% if #book.present? %>
$('#book-title').html("<%=#book.title%>");
<%end%>
And in your view, close to the link above, this will then change the text inside a html-tag with I'd book-title.
<div id="book-title">
</div>
Second:
I do not understand what you mean by
...need to return something...
Can you add an example?
Hope that this can help you a bit.
Edit:
This is my try to understand what you want to do:
In your view:
<%= hidden_field_tag :bookmarked_against_req_id, value: #data2 %>
<% if #requests != nil %>
<% #requests.each.with_index do |request,index| %>
<% if request.present? %>
<%= link_to 'Bookmark it', bookmark_request_path(request), remote: true %>
<%= request.title %>
<%= request.is_service%>
<%= request.description%>
<% if #tag[index].present? %>
<% #tag[index].each do |cat| %>
<%= cat.title %>
<%end%>
<%end%>
<%= request.created_at %>
<%end%>
<%end%>
<%end%>
In your controller:
def bookmark_request()
request_bookmarked = Request.getRequest(params[:id]) # the params[:id] should be set in the request.
bookmarked_agains_Request = Request.getRequest(params[:bookmarked_against_req_id) # This is defined in your hidden_field_tag
When your action bookmark_requestis done. If the request was AJAX you will render the JavaScript-file bookmark_request.js.erb
Here you should have the script you put in your view:
If the resource is saved, you should put JavaScript to render 'Success' or if it failed you should do otherwise.
The flash[:notice] = "Request has been bookmarked successfully."will not be understood by your AJAX-request.

Problem using form builder & DOM manipulation in Rails with multiple levels of nested partials

I'm having a problem using nested partials with dynamic form builder code (from the "complex form example" code on github) in Rails. I have my top level view "new" (where I attempt to generate the template):
<% form_for (#transaction_group) do |txngroup_form| %>
<%= txngroup_form.error_messages %>
<% content_for :jstemplates do -%>
<%= "var transaction='#{generate_template(txngroup_form, :transactions)}'" %>
<% end -%>
<%= render :partial => 'transaction_group', :locals => { :f => txngroup_form, :txn_group => #transaction_group }%>
<% end -%>
This renders the transaction_group partial:
<div class="content">
<% logger.debug "in partial, class name = " + txn_group.class.name %>
<% f.fields_for txn_group.transactions do |txn_form| %>
<table id="transactions" class="form">
<tr class="header"><td>Price</td><td>Quantity</td></tr>
<%= render :partial => 'transaction', :locals => { :tf => txn_form } %>
</table>
<% end %>
<div> </div><div id="container">
<%= link_to 'Add a transaction', '#transaction', :class => "add_nested_item", :rel => "transactions" %>
</div>
<div> </div>
... which in turn renders the transaction partial:
<tr><td><%= tf.text_field :price, :size => 5 %></td>
<td><%= tf.text_field :quantity, :size => 2 %></td></tr>
The generate_template code looks like this:
def generate_html(form_builder, method, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
form_builder.fields_for(method, options[:object], :child_index => 'NEW_RECORD') do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
def generate_template(form_builder, method, options = {})
escape_javascript generate_html(form_builder, method, options)
end
(Obviously my code is not the most elegant - I was trying to get this nested partial thing worked out first.)
My problem is that I get an undefined variable exception from the transaction partial when loading the view:
/Users/chris/dev/ss/app/views/transaction_groups/_transaction.html.erb:2:in
_run_erb_app47views47transaction_groups47_transaction46html46erb_locals_f_object_transaction'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:29:in
generate_html'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:28:in
generate_html'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:34:in
generate_template'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:4:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:3:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:1:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/controllers/transaction_groups_controller.rb:17:in
new'
I'm pretty sure this is because the do loop for form_for hasn't executed yet (?)... I'm not sure that my approach to this problem is the best, but I haven't been able to find a better solution for dynamically adding form partials to the DOM. Basically I need a way to add records to a has_many model dynamically on a nested form.
Any recommendations on a way to fix this particular problem or (even better!) a cleaner solution are appreciated. Thanks in advance.
Chris
I suggest to use another example instead of this. I went also through this process recently and the best implementation is from ryan bates this: http://github.com/ryanb/complex-form-examples/tree/unobtrusive-jquery-deep
If you are using prototype you that's not a problem, you can easily change the implementation to prototype from jquery.

Categories

Resources