How to access changing instance variables (due to a loop) in JavaScript - javascript

I am trying to use AJAX to append images to a div container. My photos have a URL field, and so I tried to create an instance variable to then throw inside a div tag like <div id="individual-photo" data-url="<%= #photo_url %>">.
This didn't work, because it assigned one value for that instance variable and when I called it in my .js var url = $("#individual-photo").data("url");, it gave me the same image for all future photos.
I found that solution in another StackOverflow and I think that would work if I wasn't working with a div generated through a loop.. so my question is, seeing as how I am using a loop.. how do I communicate this information to my .js file?
This is the code in my index.html.erb
<div id="sidescrolling-container">
<% if #page > 1 %>
<%= link_to "PREV", (next_path(#link - 2) + "/#individual-photo") %>
<% end %>
<% #pics.each do |photo| %>
<% #pic_id = photo.id%>
<% #photo_url = Photo.where(id: #pic_id)[0].url %>
<div id="individual-photo" data-url="<%= #photo_url %>">
<img src="<%= photo.url %>" height='250px' width="250px">
<span id="photo-title"><%= photo.title %></span>
</div>
<% end %>
<% if #page < #page_max %>
<%= link_to "NEXT", (next_path(#link) + "/#individual-photo"), id: "next_button" %>
<% end %>
</div>
and my .js
var images = $.get("photos/" + page, function(data){
var info = $("#individual-photo", data).each(function(){
var title = $("#photo-title", this).text();
var url = $("#individual-photo").data("url");
$("#sidescrolling-container").append(
'<div id="individual-photo"><img src="'+url+'" height="250px" width="250px"><span id="photo-title">'+title+'</span></div>'
)
})
})
If there's a better way to go about this I'd love to know more! Just no gem solutions please, I don't want to use gems for this part of my code.

$("#individual-photo") references every individual photo in your complete DOM, $("#individual-photo").data() always references the data properties of the first element in this selection. Therefore, you always get the the first url.
It should be
var images = $.get("photos/" + page, function(data){
$("#individual-photo", data).each(function(){
var title = $("#photo-title", this).text();
var url = $(this).data("url");
$("#sidescrolling-container").append(
'<div id="individual-photo"><img src="'+url+'" height="250px" width="250px"><span id="photo-title">'+title+'</span></div>'
)
})
})

Related

Params is not passing for the second time form the controller to view in Rails

I am building "comments" model for "post". Single profile will be having two tabs. Each tabs will be having ten posts. So , I am calling post using UUID (Unique Id).On first time, comments get posted and index page for comments is shown. But for the next time, without refreshing the page, comments getting posted via ajax but index page is not shown.
My comments section in Posts/index is
<% #posts.each do |p| %>
<% a = SecureRandom.uuid %>
<i class="fa fa-comment post-comment coms" data-a="<%= a %>"
style="cursor:pointer;" data-postid="<%= p.id %>" data-class="<%=
p.class.to_s %>"></i>
<%= p.comments.count %>
<div id="comments_post_<%= a %>"></div>
<% end %>
<script type="text/javascript">
var comments_url = "<%= comments_path %>";
$(".coms").click(function(e){
var p_a = $(this).data("a");
var c_type = $(this).data("class");
var id = $(this).data("postid");
e.stopImmediatePropagation()
$("#comments_post_"+p_a).toggle(
function(){($("#comments_post_"+p_a).load(comments_url+"?c_type="+c_type+"&id="+id+"&p_uuid="+p_a));}
);
});
In jquery, I am passing the UUID as p_uuid to the comments index action.
comments/controller index action is
def index
#holder = params[:c_type].constantize.find(params[:id])
#c_uuid = params[:p_uuid] unless params[:p_uuid].blank?
render partial: "comments/index"
end
I am assigning params[:p_uuid] to the #c_uuid.
comments/index is
<div class="row postComment"">
<div class="col-md-2 col-sm-2"><%= image_tag(current_user.image_url[:url], :class => "commentpic") rescue "" %></div>
<div class="col-md-10 col-sm-10">
<textarea id="commentText" class="annotation send-comm form-control" placeholder="Add a comment"
data-c-id="<%= #holder.id %>" data-c-type="<%= #holder.class.to_s %>" data-uuid="<%= #c_uuid %>"></textarea>
<div class="hint">Press Shift + Enter for a new Line</div>
</div>
</div>
<script>
var comments_url = "<%= comments_path %>";
function postComment(context){
var comment = $(context).val();
var c_type = $(context).data("c-type");
var c_id = $(context).data("c-id");
var uuid=$(context).data("uuid");
var commParams = {
commentable_type: c_type,
commentable_id: c_id,
body: comment
}
postData( comments_url, { comment: commParams }, function(data){
$("#comments_"+"<%= #holder.class.to_s.downcase %>_<%= #c_uuid %>").load(comments_url+"?c_type=<%= #holder.class.to_s %>&id="+"<%= #holder.id %>");
});
</script>
Actual problem is, I am posting first comment, its getting posted and index page is shown. But , for the second time the comments getting saved in database but its not getting shown on index or index not getting updated.
I checked with the console.log, #c_uuid from comments controller in passed to the comments/index for the first time, but its not available for the second time. Means, #c_uuid is nil for the second time.Please, help me in this.

how do i access the document dom object in ejs?

I am trying show a list of participants when the user clicks on the button.But each time i end up with an error ""document is not defined".(Please don't give me jquery!!).
<% var bt = document.getElementById("bt");
bt.addEventListener('onclick',function(){
var chatbox = document.getElementsByClassName('parti');
var msg = document.createElement('div');
msg.setAttribute('class', 'participants');
msg.textContent('Participant \n\n\n'); %>
<%= chatbox.appendChild(msg); %>
<% }); %>
Change this line:
bt.addEventListener('onclick',function(){
With this:
bt.addEventListener('click',function(){
When we use addEventListener we don't need to use prefix 'on' for even name.
Also, you have used getElementsByClassName and for this you need to iterate over array, so use:
<%= chatbox[0].appendChild(msg); %>

How can I send an automatically generated ID for a form element to a javascript function?

I am trying to call a javascript function from my form page in a Rails 3 project. I need to send the function the ID of a particular element. Unfortunately I can't get the ID easily since it is automatically generated by a plugin.
I tried doing it this way:
<%= t.select :number_type, #id_types, {}, {:onchange => "has_other_field(' + the_value.id.to_s + "');"} %>
<% if (!the_value.nil?) && (!the_value.number_type.nil?) && !#id_types_sm.include? the_value.number_type) %>
<script type="text/javascript">
setup_other_field("<%= the_value.number_type %>", ###ID WOULD GO HERE###);
</script>
<% end %>
.. But since I don't know the ID of the element, I can't call it from the function.
So now I'm trying to do it this way, by calling the function from an "onload" when the input element loads:
<% if (!the_value.nil?) && (!the_value.number_type.nil?) && (!#id_types_sm.include? the_value.number_type) %>
<%# Call the function from the form helper only if the conditions are met %>
<%= t.select :number_type, #id_types, {}, {:onchange => "has_other_field(this.id);", :onload => "setup_other_field('" + the_value.number_type + "', this.id);"} %>
<% else %>
<%# Use the form helper without calling the function %>
<%= t.select :number_type, #id_types, {}, {:onchange => "has_other_field(this.id);"} %>
<% end %>
BUT I realize that onload does not work for this situation. Is there any workaround for this? How can I either
A) get the element ID from the field to the function in the first option, or
B) call this function from this input element whenever it loads?
... or C) an alternative way to do this?
Thanks in advance and let me know if more details would help.
If you have ID saved in the model, get it with <%= model.id %>
Exception to this rule is when you create object, and it is before it is written to database. If you go to edit or anywhere else it will be ok.
If you have it somewhere on the page :/ then you can use jQuery to get it for you.
< div id="id_of_the_element" attr_with_my_id="15" >ABC< /div >
$("#id_of_the_element").attr('attr_with_my_id')
< input id="id_of_the_element ... >< /input >
$("#id_of_the_element").value

JS and Rails site wide announcements

Tried doing http://davidwparker.com/2008/09/17/site-wide-announcements-in-rails-using-jquery-jgrowl/
Am really bad with JS. Think I am messing up on the last part where it says "This code goes in your application.js file (somewhere in $(function){ //here })"
Am I not suppose to do a link_to_function and create a function with this code that references that link?
Really lost on this one.
Updated -
application.js looks like
$(document).ready(function() {
$.jGrowl.defaults.closer = true;
$("#announcements_box").css("display", "none");
$("#announcements_box .announcement").each(function(){
$jQuery.jGrowl(this.textContent,{ sticky:true, close:function(e,m,o){hide_announcements();} });
});
});
function hide_announcements(){
$.get(
'/hide_announcements'
);
$("#announcements_box").fadeOut();
return false;
}
And my application.html.erb has
<% unless current_announcements.empty? %>
<div id="announcements_box">
<% for announcement in current_announcements %>
<div id="announcement_<%= announcement.id.to_s %>" class="jGrowl">
<%= announcement.message %>
<%= link_to "Hide Annoucements", hide_announcements_path, :id => 'hideAnn'%>
</div>
<% end %>
</div>
<% end %>
I'm not sure what $(function){ //here } notation means, that should give you error in the browser, but I think he just wants to execute code after page is loaded:
$(document).ready(function() {
// here
}
And the culprit was I only entered a div ID when I needed to have a div ID and class.

Is it right to generate the javascript using C# in ASP.NET MVC view page?

[Sorry for long question but it is necessary to explain the problem]
I am working on a learning website and it is supposed to show a list of messages to user if there are any. Something like this:
When user presses close button, that message must be marked "read" and should not be shown next time. Following code is used to generate those messages:
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" value="Close<%= Html.AttributeEncode (m.ID) %>" id="c<%= Html.AttributeEncode (m.ID) %>"/>
<% } %>
</div>
<% } %>
After that, following the guidelines, I added the support of http post method in controller which marks the message as read and then refreshes the view (to handle disabled JavaScript):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CloseMessage (int id) {
using (var dl = new DL ()) {
dl.MarkAsRead (id);
}
if (Request.IsAjaxRequest ()) {
return new EmptyResult ();
}
else {
return RedirectToAction ("Index");
}
}
Then I wanted to add JavaScript support such that only the message goes away (using jQuery). But the problem is that I am generating the buttons and messages programmatically.
So ended up with a weird looking javascript code in viewpage:
<script type="text/javascript">
$().ready(function() {
<% foreach (var m in Model.UserMessages) { %>
$("#c<%=Html.AttributeEncode (m.ID) %>").click(function(event) {
$.post("Home/CloseMessage/<%=Html.AttributeEncode (m.ID) %>");
$("#m<%=Html.AttributeEncode (m.ID) %>").slideUp("slow");
event.preventDefault();
});
<% } %>
});
</script>
This is basically creating the javascript code in a C# loop which actually works but too much for me to digest. Is there any better way of doing this?
You could just create one javascript function that takes the element IDs as parameters :
function myFunction(ID) {
$.post("Home/CloseMessage/" + ID);
$("#m" + ID).slideUp("slow");
}
And :
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" value="Close<%= Html.AttributeEncode (m.ID) %>"
id="c<%= Html.AttributeEncode (m.ID) %>"
onclick="myFunction('<%=Html.AttributeEncode(m.ID)%>')"/>
<% } %>
</div>
<% } %>
YOu could uses a CSS selector in your JS to get all buttons with a particular class assigned to them. Then you can wire up you click event to them. So your HTML would be something like this:
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" class="MyCloseButton" value="Close<%= Html.AttributeEncode (m.ID) %>" id="c<%= Html.AttributeEncode (m.ID) %>"/>
<% } %>
</div>
<% } %>
I've only added the class="MyCloseButton" to your input
Then in your JS (I use mootools but JQuery has CSS selectors too but you will need to port it sorry) you can do something like this:
window.addEvent( "domready", function() {
$$("input.MyCloseButton").each( function( button ) {
// Add your code here, you can reference button.id etc for each of your buttons
}
});
This way you only have to write out one little function in plan JS and not worry about doing it server-side, all you need to do it decorate your buttons with a css class so the JS can find them.
I understand its not pretty, but its not that bad either. I think there are easier ways to do this, however.
You can use jquery's positional selectors from the button's click event handler. Then just assign the same handler to every button.
<script type="text/javascript">
$(document).ready(function() {
$("input[type=submit]").click(function(){
$(this).parent().slideup("slow");
$.post("Home/CloseMessage/" + $(this).parent().attr("id"));
event.preventDefault();
});
});
});
</script>

Categories

Resources