rails infinite scroll ajax actions on page > 1 items - ruby-on-rails

Let me first state that this is an instance of using a lot of other peoples' code and not completely understanding what's going on and how to fix my issue.
I followed the Railscast for infinite scroll using will_paginate, and have that working fine.
I load 12 items per page, each in it's own partial. Each item is an object that a user can 'like' by clicking a 'thumbs up' button.
I ajax-ified this button, and reload the partial for the item that is 'liked'.
This works fine on items 1-12 (the first page).
When a user clicks the thumbs up button on an item that is loaded via infinite scroll, the ajax call executes, but doesn't find the object again, and the partial simply goes blank.
Here's my code-
##messages partial
<div class="span3 well" style="height:360px;" id="message-<%=message.id%>">
<div class="thumbnail">
<%= image_tag message.gif.url %>
<div class="caption">
<h5><%=link_to message.sender, "/profile/#{User.find_by_username(message.sender).id}"%></h5>
<h5><%=message.chain.subject %></h5>
<p><em>"<%= message.content %>"</em></p>
<p><a href="/upvote/<%=message.id%>" data-remote="true" class="btn btn-success"><%=message.up_votes%>
<i class="icon-thumbs-up"></i> Nice Work</a>
</div>
</div>
</div>
# js.coffee (from railscast)
jQuery ->
$(window).scroll ->
url = $('.pagination .next_page').attr('href')
if url && $(window).scrollTop() > $(document).height() - $(window).height() - 50
$('.pagination').text('Loading more gifs...')
$.getScript(url)
# vote.js -- js executed by ajax call
$("#message-<%=params[:id]%>").load(location.href+" #message-<%=params[:id]%>>*", "");
I'm pretty certain the problem is in the vote.js. the .load(location.href+" #message-<%=params[:id]%>>*", ""); seems to not be able to find the objects on the 2nd, 3rd, 4th, etc. pages because it uses location.href which, as the current url, only supplies the first 12 objects. I think I need to somehow put the page in that url, but I'm not sure how to accomplish that.
EDIT-
Alternatively, maybe I should have an endpoint for all messages that isn't paginated, and call that url instead of location.href + ?

This issue seems to have resolved itself.
It's funny it didn't seem to work locally, but is working on Heroku.
If anyone has an explanation for this I'd love to hear, but otherwise this is solved!

Related

Display selection of index in a partial

I've been trying to solve the following challenge all day without any luck.
When going through forum posts I came across jQuery and AJAX which are both new concepts to me and which I'd rather skip for now, if possible.
I've got a partial, "navbar-left", which shows a list of all bank accounts in my model Account.
When the user clicks on one of the items in the list, all transactions of that account should be shown in the same page at the right. The partial below links to a new page which is not how I'd like it.
The navbar-partial:
<ul class="nav nav-pills nav-stacked">
<% #accounts.each do |account| %>
<li role="presentation"><%= link_to account.account_holder, account_mutations_path(account.id) %></li>
<% end %>
</ul>
Any tips on how to get this fixed is much appreciated!
The page with the navbar at the left
The mutations in a separate page instead of a partial
Either you're sending viewers to a new page, or dynamically loading content within their current page.
If the latter, then the only solution is AJAX.
Luckily, Ruby on Rails makes transitioning from one to the other very easy.
Here is a gist of how it works:
<%= link_to account.account_holder, account_mutations_path(account.id), remote: true %>
This was pointing back to some page previously (e.g. action.html.erb).
Because of remote: true, it's going to be sending JS directly to the browser instead of a new HTML page (e.g. action.js.erb in the same view folder and same action name).
Here we can control the behavior we want by rendering a partial using ERB and using JS to change the HTML content of some part of the page:
// action.js.erb
$('#some_element').html('<%= j render "partial" %>')
Which will insert the HTML of the partial directly into the JQuery that changes the content dynamically.
Where j is a shorthand for escape_javascript.
Without escaping, the Ruby output is interpreted as file output and newlines would break your JS.
Example JS output without escaping:
// Bad
$('#some_element').html('<span>Content</span>
<span>More Content</span>')
Example with escaping:
// Good
$('#some_element').html('<span>Content</span>\n<span>More Content</span>')
http://guides.rubyonrails.org/working_with_javascript_in_rails.html
https://launchschool.com/blog/the-detailed-guide-on-how-ajax-works-with-ruby-on-rails
There are more great examples online and even Railscasts.
Really AJAX is the best way to do this, and it's not as complicated as you might think. But if you really want to skip AJAX then your best approach is probably to load ALL transactions for all accounts, in different div's and then show or hide them based on which is clicked.
For a rudimentary introduction to this look at javascript tabs... you click on a tab, the appropriate information is shown.
http://www.w3schools.com/howto/howto_js_tabs.asp
You can do this very simply without ajax. The big difference would be - it's not the same page. One page would be the account#index (as you have now), the other page is the account#show page.
For the show page, use a very similar view as the index page, the left side would include the partial with one of the account li class="active" to highlight the account you are currently on. For the right side of the page, render the account mutations list items.

Delaying load of page contents until menu item clicked in a multi-page template

I'm not sure I understand what's possible with multi-page templates in JQM so I need a bit of help. I'm using version 1.4.5.
Let's say my app has only two pages (Page A and B) generated by a multi-page template. It takes the server several seconds to generate each page because they require many database calls and data processing. Currently, this multi-page template is generated by a single script on the server, index.pl.
Both pages are accessed by the user through a navbar. Page A is the first page in the template so it's visible to the user first.
To speed up the app, I want the HTML for Page B to get generated and fetched from the server only after the user taps the navbar menu item for Page B.
After Page B loads, the user should now be able to switch between pages instantly since the content for both pages are loaded into the DOM.
What is the proper way of accomplishing this desired result?
Do I tie the navbar tap on Page B to an ajax call and inject the server response into Page B? This seems kludgy.
I'm thinking I'm missing something fundamental about JQM but I'm not sure what. Can someone help?
SERVER-SIDE SCRIPT PSEUDOCODE:
<!-- PAGE A -->
output <div data-role="page" id="page_a">
output <div data-role="navbar">
output <ul><li>Page A</li>Page B<li></ul>
output </div>
output <div role="main" class="ui-content">
generate_html_page_a();
output </div>
output </div>
<!-- PAGE B -->
output <div data-role="page" id="page_b">
output <div data-role="navbar">
output <ul><li>Page A</li>Page B<li></ul>
output </div>
output <div role="main" class="ui-content">
generate_html_page_b();
output </div>
output </div>
For your architecture the best approach is single page template but you can use the pagecontainer API to load any page programmatically.
$(":mobile-pagecontainer").pagecontainer("load", "about.html", { role: "dialog" });
Check the jQM docs for more information.

Jquery Mobile Javascript not working on ajax load

Have the following markup in my html page to toggle a search bar based on if a search icon is clicked:
<a id="searchIcon" href="/"></a>
<div id="searchWrapOuter" style="display:none;">
<div id="searchWrapInner">
<div id="formContainer">
<form id="searchForm" action="#">
<div>
<input type="search" name="search-mini" id="search-mini" value="" data-mini="true" />
</div>
</form>
</div>
</div>
</div>
Width the following javascipt/jquery:
$(function() {
$(document).on("click", "#searchIcon", function () {
var searchWrapper = $("#searchWrapOuter");
$(searchWrapper).slideToggle();
return false;
});
});
This code works as expected on a page load direct off a Url. When coming into the page off a link which is Ajax loaded, loads the contents of the page into the DOM, and the DOM ready handler only executes for the first page.
I have read about using the
$(document).on('pageinit'), not $(document).ready()/$(function()
I still haven't been able to get this to work when coming in off an ajax link however. What would be the correct way to implement these events to get the code to work coming in from an Ajax link?
Thanks,
Most likely it is because you are using IDs instead of classes. jQuery Mobile doesn't work well with IDs because it caches pages into the DOM so if you open a page, close it, then go back to the page, you might have your page twice inside the DOM (one visible, one hidden/cached). So when you do $("#searchWrapOuter") you don't know which element you are actually dealing with (in your case, probably the hidden one).
The solution is to change your IDs to classes. This is not very intuitive but I found that is the best way to work with jQuery Mobile.
Also note this comment in the doc which might also be relevant to you:
The id attribute of all your elements must be not only unique on a given page, but also unique across the pages in a site. This is because jQuery Mobile's single-page navigation model allows many different "pages" to be present in the DOM at the same time. This also applies when using a multi-page template, since all "pages" on the template are loaded at once.
http://jquerymobile.com/demos/1.2.0/docs/pages/page-anatomy.html
You can manually adjust delay time to 500ms and 1s.
$(searchWrapper).delay(1000).slideToggle();
My issue is that the page id was below the pages tags. So once I moved the page div above it, the javascript was included in the ajax page load. Previous to this

How can I load a div in rails in response to clicks on another div?

I'm very new to Rails (and web) programming, so I'm not even sure what technology I should be looking for for this.
I've downloaded and run through the first five chapters of the Rails tutorial, but now have a very simple request.
On the left hand side of a web page, I will have a table. If the user clicks on an element in that table, I want to have the right hand side of the page show something new.
I already have a page to display the table, viz:
<div class="center hero-unit">
<div class="container">
<h2>2012 Yearly Report</h2>
<div class="row-fluid">
<div class="span12">
<div class="span4">
<table border="1">
</table>
</div>
<div class="span6">
<!-- load stuff here based on what someone clicks on in the table -->
</div>
</div>
</div>
</div>
</div>
And I'm using bootstrap layouts to display everything. I just don't understand how to change the contents of the 'span6' div based on user behavior in 'span4'.
This is a difficult question to answer. It really depends on what kind of data you're trying to display and what sort of interactivity you're looking for.
You don't really provide much information about what you're trying to accomplish, but if I had to guess, you're trying to load data from your database and insert it into an element without leaving the current page. This is what AJAX is for (your tutorial goes into it a bit in chapter 11) and involves a good deal of javascript, which is generally beyond the scope of a server side language like Ruby. Luckily, rails includes helpers for making it easy to include AJAX features into your web application without having to write a lot of javascript (although you'll have to write some).
As an example, suppose your table has a list of articles, and you want to display the contents of an article in a div when its link is clicked on.
First the link:
<%= link_to article.name, article_url(article), :remote => true %>
The remote option tells Rails that it's an AJAX link.
Next, you need to render a javascript template for your article's show action. You'll name it show.js.erb.
Supposing the div you want the data to be loaded into looks like this,
<div id='article-content'></div>
you'll want your show.js.erb to contain the following:
$('#article-content').html("<%=javascript_escape #article.content %>");
This javascript (with embedded ruby) code will be evaluated when one of your remote links is clicked and will replace the content of your div with the article's content.
There is plenty of resources online to give you more information. It looks like railscasts just released an episode on this topic just a week ago. It requires a subscription to view, but is well worth it (especially if you're just starting out).

RJS method outputting raw javascript

I've got a page where I'm dynamically adding elements to a from a series of select boxes. I'm using RJS to do this and it's working great. Now, these elements in the div are a series of that are accompanied by Delete buttons, in case the user wants to remove a textarea. Here's where I'm hitting a wall.
Here's the code that runs the Delete button. This is working well to my knowledge:
<%= link_to image_tag("/images/button_delete.gif", :alt=>"Delete"), :controller=>"report", :action=>"remove", :id=>#sentence.id %>
In my report controller, I've got this very simple method being called by the above code:
def remove
#sentence_id = params[:id]
end
Again, I think that's working. Now, when I activate this action by hitting the button, off we go to the RJS file, remove.rjs:
page.remove 'sentence_'+#sentence_id
And here's what I get in my browser, instead of a happily removed element!
try
{
Element.remove("sentence_63");
}
catch (e)
{
alert('RJS error:\n\n' + e.toString());
alert('Element.remove(\"sentence_63\");');
throw e;
}
My understanding is that this happens when there's no page in the current context. Online documentation on this is kind of thin.
Any help appreciated!
Cheers,
Aaron.
Try link to remote. That will build the ajax call for you and should remove the element from the page.
Then link_to_remote syntax is slightly different than the link_to syntax, so don't let that trip you up either.
Since your remove function doesn't seem to actually delete a record, if you just want to remove an HTML element from a page you can use link_to_function with the Prototype remove() method for Elements. In addition, if you've got a recent version of Rails (for example, 2.3.2) you can take advantage of the dom_id helper to auto generate the sentance_id ID attribute
<%= link_to_function(image_tag("button_delete.gif", :alt=>"Delete"), "$('#{dom_id(#sentence}').remove();" %>
An approach like this could help keep the number of methods down in your controller (unless you intend on doing something else in the controller)
Your Delete link is setup as a normal link, i.e.
<a href="/report/remove" id="sentence_63">
<img src="/images/button_delete.gif" alt="Delete" />
</a>
which triggers a normal HTTP request. Since your intent is to trigger an AJAX request, try PJ Davis' recommendation and use link_to_remote

Resources