Get event target after frame loads - Turbo Rails - ruby-on-rails

I have some turbo frame forms in my page that should fire some javascript after they are loaded into the document. Therefore I'm using the turbo:frame-load event listener. To access the <turbo-frame> element I'd like to use the event's target, as mentioned in the documentation (https://turbo.hotwired.dev/reference/events):
turbo:frame-load fires when element is navigated and finishes loading (fires after turbo:frame-render). The specific element is the event target.
Here my code:
document.documentElement.addEventListener('turbo:frame-load', function (e) {
console.log(e.target);
});
However this returns not the <turbo-frame> element, but the <html> element instead. Does anyone know how to get the <turbo-frame> instead?

Related

jQuery .on() not working with jquery-ujs

So I have a rails app that renders views via jquery-ujs. (data-remote in the URLs, then a load of js.erb files with things like:
$('#whatever').html('<%= j render("form") %>');
In my main JS file, I have event handlers like so:
$('.action').on('click', function() {
console.log("clicked");
});
but the on() behaviour does not attach to the new elements inserted by jquery-ujs. I can go into the console and paste the above code and everything attaches fine (once the elements are already there), but straight after ujs fires, no luck. Is this a bug or am I doing something wrong?
This is with jQuery 1.9.1 and Rails 3.2.13 btw.
You need to bind on to a parent like document. Now, you're binding directly to the .action element, which is essentially the same as using $('.action').click(). Because you're adding elements to the DOM later, you need to delegate the handler to something that's already present before the elements are inserted. You can provide a selector as the second parameter of the .on event to bind it to .action.
Have a look at the 'Direct and delegated events' section in jQuery's API documentation for .on.
This should work:
$(document).on('click', '.action', function () {
console.log('Clicked!');
});
Since #whatever seems to be static (exists all the time) you can delegate the handling to it..
$('#whatever').on('click','.action', function(e){
console.log("clicked");
});
(assuming that the .action elements are added inside the #whatever element)
See http://api.jquery.com/on/#direct-and-delegated-events for more on delegated events

How to create JQuery-UI widgets dynamically

I understand that I can use .on to bind functions to DOM elements when some event occurs on an element.
I have been using JQuery-ui, and I want to create different JQuery-ui elements once they have loaded on the page. For example, create a button when one is loaded on the page:
$(document.body).on('load', '.my-button', function(){
$(this).button()
});
However, this doesn't work (in fact, the handler is never reached).
How can I create JQuery-ui widgets when they load in the DOM?
jQuery does not fire any events when an element is created. Instead, use the watch plugin and run your button()s from there.

jQuery Mobile - firing pageshow event only once

I am trying to execute a snippet of JS only once, after the page has completely loaded and JQM has taken care of all the ui modifications (i.e. listviews, buttons, etc.). I do want it to execute only on that page, and not on subsequent pages.
What I tried first, was pageshow
<script>
$('[data-role=page]').live("pageshow", function() {
alert("Ready!");
});
</script>
This has the problem that the function is now attached to the page div and gets executed every time any subsequent page gets shown. However, I only want this to be executed once, and only for the page that contains that JS snippet.
Is there a way to listen to the pageshow event, without actually attaching the function to it.
The only way I was able to do it was by binding and unbinding like this:
<script>
$('[data-role=page]').bind("pageshow.test", testfun);
function testfun() {
alert("Ready!");
$('[data-role=page]').unbind("pageshow.test", testfun);
}
</script>
But is there a more elegant way to do so?
jQuery has a one function to bind an event handler to be executed only once. Check the reference.
The pageinit event fires once per page just after the jQuery Mobile framework initializes its widgets; I think it may be what you're looking for.
pageinit
Triggered on the page being initialized, after initialization occurs.
We recommend binding to this event instead of DOM ready() because this
will work regardless of whether the page is loaded directly or if the
content is pulled into another page as part of the Ajax navigation
system.
Source: http://jquerymobile.com/demos/1.1.0-rc.1/docs/api/events.html
If you want to bind to a specific page and not the rest, then select only the page you want to alter... Here's an example:
<script>
$(document).delegate('#my-page-id', 'pageinit', function() {
alert("PageInit!");
});
</script>

How to use pageinit correctly?

I have a single file for each page and i am trying to implement the pageinit event handler on every page (I think what belongs strictly to one page, should be declared there) as shown below:
<body>
<div id="myPage" data-role="page">
<!-- Content here -->
<script type="text/javascript">
$("#myPage").live('pageinit', function() {
// do something here...
});
</script>
</div>
</body>
The event is bound properly to the page, so the code is executed but - now my problem - if i go to another page and return later on the pageinit event will be executed twice. I think that is because the .live method binds the pageinit event again to the page. But shouldn't the pageinit event only called once at page initialization? What I am missing here?
I solve the issue by passing the name of the event, in this case the "pageinit" instead of the handler.
<script defer="defer" type="text/javascript">
var supplier = null;
$("#pageID").die("pageinit"); //<--- this is the fix
$("#pageID").live("pageinit", function(event){
console.log("initialized - #(ViewBag.ID)");
supplier = new Tradie.Supplier();
supplier.Initialize("#(ViewBag.ID)");
});
Ref: http://www.rodcerrada.com/post/2012/04/26/jQuery-Mobile-Pageinit-Fires-More-Than-Once.aspx
I think its probably best to move your JavaScript code into another file as while your navigating around your site jQuery Mobile may cleanup (read: delete from DOM) that myPage page and therefore will have to load it in again and hense rerun that same block of code you defined and bind 2 listeners for the pageinit event.
Thats basically why they suggest using the live or on functions however it falls over if you include the binding code on the page ;)
However if you insist on having your code placed on a per page basis than use bind instead of live.
Ref: http://jquerymobile.com/demos/1.0/docs/pages/page-cache.html
jQuery Mobile therefore has a simple mechanism to keep the DOM tidy. Whenever it loads a page via Ajax, jQuery Mobile flags the page to be removed from the DOM when you navigate away from it later (technically, on the pagehide event).
I'm pretty sure they recommend binding pageinit to the document using on(). E.g.
$(document).on ('pageinit', '#myPage', function (event) {
instead of having the pageinit bound to the page, which is getting re-inited. In fact, I thought $(document).on() was the recommended way to bind events in jQuery, in general, now.
A quick workaround I have used is declaring a variable containing the handler function.
var handler = function() {
// your code
};
Then always use die() before binding the handler with live()
$( "#myPage" ).die( handler ).live( handler );
I'm sure this is not the intended usage by the authors, but it does the trick, you can leave your code within the page DIV.
$("#page1").live("pageinit", function () {
alert('pageinit');
$("#page1").die("pageinit"); //<--- prevent from firing twice on refresh
});

How to make getJSON to update correctly an element after page loaded in jQuery Mobile?

I'm trying to get a getJSON result to update an HTML element on page load, within a jquery mobile loaded website.
Now, I've read I should not rely on ready(), but bind to pageInit. So I tried, but it just won't work. I've tried many other events that could be logical to try within the API event documentation, without any success.
The closest I come to success is after the page is loaded, via ajax, if I refresh the page manually (with the browser's refresh button), getJSON does update the corresponding HTML element. And you guess, it's not what I want to achieve. Here is what the code looks like now, and where it is placed...
<div data-role="page">
<script>
$( '#pageContainer' ).live( 'pageinit',function(event){
//an alert() here does fire right before the page is shown in the browser
//here is the getJSON code.
});
</script>
Now, I need help to try to figure how to make it work. I only want an element X in the page to update with the text returned from a jSON when the page appears in the browser! Like a normal ready() function would have done !
(Maybe it is relevant to specify I'm running RC2 ?)
If you can't use JSONP here, have you tried setting a setTimeout()? You have to trigger a callback after the json object is loaded so timing is essential.

Resources