How to do history.js in Rails the right way? - ruby-on-rails

Hi everyone,
it's now my fourth try to implement history.js in a Rails app. I have one approach that is running quite okay, but the code is so ugly. Today again I looked at the code and thought: How can I make this better, easier, more DRY?!
What I have done so far (and working quite okay, not perfect):
Set remote: true to my links
jquery-ujs fetches the js.erb
My HTML looks like:
<body>
<div id="content">
some content with buttons, etc.
</div>
</body>
The js.erb contains:
History.pushState(
{
func: '$(\'#content\').html(data);',
data: '<%= j(render template: "news/index", formats: [:html]) %>'
},
'test title',
'<%= request.url %>'
);
And then history.js takes the function and gives it the data. So it replaces the content-div with the new generated code. And it also updates the URL. This code I have to put in every(!) js.erb file.
My last thoughts to make it a bit less ugly were:
Set remote: true to my links
When a link gets clicked it fetches some js.erb which replaces the content-div
All links with data-remote="true" will get a ajax:success-handler
On ajax:success the new URL gets pushed to history.js
But there's still one problem within. Then I have JavaScript code:
$(document).on('ajax:success', 'a[data-remote="true"]', function() { ... });
The problem is: ajax:success never fires if I replace the div-tag where the link (that should fire the event) was in.
Maybe someone can solve my problems...
Or is there a better way?

I only use jquery-ujs and pushState, popState.
See my answer here:
https://stackoverflow.com/a/27532946/345996

what about:
History.Adapter.bind(window, 'statechange', function() {
var state = History.getState();
...
});

I'm using the beforeSend event as global listener for all data-remote to change the handle the history of the browser.
I prefer the beforeSend because I want the link to change as soon as it is clicked, regardless of the result of the ajax request...
$(document).bind('ajax:beforeSend', function(event,data){
history.pushState(null, '', event.target.href)
});
This solve your problem because the event is fired before any modification to the DOM is done.

Have you tried turbolinks ?
It will be default in Rails 4.

Related

Updating part of a page by triggering an action on an interval

I'd like to have just a part of my page updated every second. I know I can get this to work using setInterval in JavaScript but what if I want some logic built into my Rails code? Here's a simple abstraction:
Code in controller:
def lookup_something
#stuff_to_display = [code to look up a set of records]
end
Then in the view:
<body>
<div id="update_this"></div>
</body>
I'd like something to run that action every second and update the div above. I know I've done this before in a previous project with a relatively simple block of code but I can't find out how to do it again for the life of me.
If you are willing to use jQuery, the $.ajax call is fairly straightforward:
From http://api.jquery.com/jQuery.ajax/
setInterval(function() {
$.ajax({
url:"url/to/lookup_something",
success:function(result){
// do something here to
// $("#update_this")
}
});
}, 1000); // every second

mobile.changepage requiring page refresh

I'm using $.mobile.ChangePage() to navigate from one HTML page to another. But the contents of the page is not changing. while doing so the page URL changes but the new page is not loaded. it requires to be refreshed to load.
you should use JavaScript function to change the page..using
window.location = 'your page ';
hope it will resolve your problem !
In the code that you provided in the comments above, you are likely getting an error stating that next_page is not defined. Given that you are dealing with jQuery Mobile, try assigning the click handler slightly differently:
Change the definition of the link to something like this:
<a id="btnNextPage" href="#" >Details</a>
You don't have to give it an id - you could just use selectors to identify the link in the following javascript:
// the event handler
function next_page() {
$.mobile.changePage("http://www.google.com", {transition:"slide"});
}
// assign the click event when the DOM is ready
$(function() {
$("#btnNextPage").click ( next_page );
});

jquery mobile, pgaechange and pageload not work

I am trying to use ajax to load sometag , but my appended code is not being enhanced by JQM.
I tried $(this).trigger('create') and $(this).trigger('updatelayout') but It still not working.
Then I tried to call ajax by function jquery mobile support: $.mobile.changePage()
my code:
$.mobile.changePage({url:'/', data:'add_new_tag=true', type:'GET'}, 'slide', false, true)
in action index: I render 'index.html'
I have checked it in firebug and see response is right (expected) . But I see nothing change in my browser.
Did I miss something ? I hope to recieve your help . Thank you :D
I have never been able to get the trigger('create') method to work for me either. Maybe someone else *cough (Jasper) can help me out with that part of the answer. I may be able to help you with your changPage code though.
Try this for changePage instead:
$.mobile.changePage( '/',{
data: "add_new-tag=true",
type: "get",
transition: "slide"
});

Trying to understand - HTML replacements and scripts having access to replaced elements on the page

I have a page with a ticket list. In it, there is a <td> that is either a grab or release link. That link inside the '' is wrapped in a '' for an ajax html replacement. Like:
<td>
<div id="ticket_grab_release_<%= ticket.id %>">
*---- either a grab or release link here ----*
<div>
</td>
So, the user clicks on 'grab': They are assigned the ticket, the worklist is updated with their info on the page via HTML replacements, and the grab link is replaced with a 'release' link.
Next to this is a 'complete' link. When the user clicks on that, a small complete form opens in a jQuery UI-Dialog window. I ran into a problem though because along with the grab/replace link changing I also had to toggle this 'complete' link with a grey non-link 'complete' or an actual 'complete' link (if ticket released - disable complete link or visa versa).
The problem is that if this 'complete' link was greyed out and I replaced that with a 'complete' link, the UI Dialog window would not open. Like (no idea what I'm saying) the link wasn't in the DOM.
I got frustrated for a bit and then tried wrapping the script in a <div> and doing an html page replacement on the whole script. I HTML replaced the greyed out 'complete' with a 'complete' link and then HTML replaced the script right after. Interestingly that worked, but I'm really curious as to why it worked. When you ajax insert a script through an HTML replacement, does that inserted script have access to the modified DOM where the original script only has access to the what was the original DOM from the page load?
<div id="html_replace_sript">
<script type="text/javascript">
$('.complete_ticket_link' ).click(function(){
var url = $(this).attr("href");
$("#form_load").load(url,
function() {
$(this).dialog({
modal:true,
draggable: true,
resizable: false,
width:'auto',
height:'auto',
title: ' Complete Ticket ',
position: [125, 50]
});
});
return false;
});
</script>
</div>
Thanks - much apprecaited!
Check out live()'s much less recource-demanding counterpart: delegate()
Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.
That means that instead of having to look through the entire window for an element, it starts at the specified root, significantly reducing overhead. This is the best solution for your issue.
The answer is YES.
But if you want to bind events to elements that match the selector now and in the future, you can use .live()
So you'd do:
$('.complete_ticket_link' ).live('click' function(){
...
});
Using this, your code can be on your main page and it will work.
Hope this helps. Cheers

Jquery UI panel resizing on click

I am using Jquery Ui panels.([http://code.google.com/p/ist-ui-panel/][1])
While loading the application, everything is fine like collasible, draggable etc.
But i want to make the panel collapsible while clicking on some links.fo ex:
This code will run when the form is loading....
$('#myNews').panel({
'collapsible' :true,
'stackable':false,
});
The html
<div class="panel" id="myNews" >
<h3>Poll</h3>
<div>Some content</div>
</div>
I want to make 'collapsible' :false when clicking some link.... like this
$('#click1').click(function() {
$('#myNews').panel({
'collapseType':'slide-right',
'collapsible':false,
});
});
the code is running without any error, but the '#myNews' not getting affected when clicking the '#click1' link.
Need some help pls.
Thanks in advance
I'm the one behind ist-ui-panel, and Jesse was right — by now the only way for you is to use 'destroy' method somewhat like:
$(document).ready(function(){
$('#click1').bind({
'click': function() {
$('#myNews').panel('destroy');
$('#myNews').panel({
'collapsible' :true,
'collapseType':'slide-right',
'stackable':true
});
}
});
$('#click2').bind({
'click': function() {
$('#myNews').panel('destroy');
$('#myNews').panel({'collapsible': false});
}
});
});
Notice, you should explicitly destroy previous panel before making a new one.
If you read the uncompressed source code for that widget, it appears that what you are doing is only meant to be used to create panels, not to modify them afterward.
The underlying software is either buggy or I don't understand it. So you'll have to hunt down some bugs, but you can use the 'destroy' method on that widget to reset the div completely, and then make it a panel again, like so:
$('#myNews').panel("destroy");
$('#myNews').panel(...
As I said, it's buggy or I don't quite get it - there's an error raised by the destroy call which you have to catch, and subsequent calls to make new panels do make panels, but they aren't completely correct.

Resources