html/js: is there a "page loaded" event in single page applications? - javascript

I'm building a single-page-application which (pre-)loads the content of different pages via ajax. when the user navigates, the app replaces the old content inside a specific tag with the new content (ajax data). this new content could be e.g. an article containing text and images.
my question is: is there an event that is fired, after replacing the content and every external resource of the new content is loaded? like a "dom ready" for a refresh of the DOM?

Yes, jQuery has a document.ready event that should work for you.
You can however replicate jQuery's event, if you don't want to import the library.
Edit
Turns out I wasn't paying attention.
No events are being fired when the DOM is modified, so it's not possible to add a listener on anything like that.
You will have to keep track of the modifications on the DOM, manually. You could add "callbacks" to the modification functions you use:
function addSomethingToPage(data){
data.doSomething():
domReady();
}
function domReady(){
//re-usable "callback"
}

Related

Add event listener after a table loads

Small-context:
I am working with django templates. There is a table that is generic in structure and thus is being used at more than once place. Now, there is a button in the table to print a PDF document. I have a web page where that table is loaded in two different places with a small difference. At one place it is loaded directly by calling the include tag. But, on the other place, it is being loaded via Ajax. Now, one may ask why two different ways to which I can only answer: nature of the workflow of that component (legacy s/w).
Issue:
Coming to the main point. I have created a Javascript file that takes care of handling the print related workflow. Initially that Javascript file had an eventlistener attached to the button which is set to activate when it is clicked.
jQuery().ready(() => {
jQuery('.dna-sample-material-page-button').on('click', printDnaSampleLabelMaterialPageHandler)
})
But, due to the differences in the way the table is being loaded, the event listener works only for the table being loaded directly but not on the one loaded via Ajax.
To overcome that issue, I tried the following:
jQuery().ready(() => {
jQuery('.samples-table-unit-part').on('load', () => {
jQuery('.dna-sample-material-page-button').on('click', printDnaSampleLabelMaterialPageHandler)
})
})
where '.samples-table-unit-part' is the class associated to the table loaded via Ajax.
But, it does not work. My main motto is to add event listeners to all the buttons belonging to the table. Is it the correct way to add an event listener. If not what can be done?
In cases of content added after DOM ready event use event delegation.
Try something like this:
jQuery('.samples-table-unit-part')
.on('click', '.dna-sample-material-page-button', printDnaSampleLabelMaterialPageHandler);
Unlike <iframe/>, <object/> and <img/> elements, <table> or any other static HTMLElement do not have load events, so you load event on .samples-table-unit-part will never fire.
You should locate the part of the code where the table is loaded with AJAX and attach your event listener only after inserting the table in the DOM.

How can I wait until a web page has loaded and all controls have been populated before executing my javascript?

Okay so I know the question reads like I'm yet another person who doesn't know how document.ready works, but this is a bit different.
Basically I'm upgrading an old web forms application that depends on a lot of proprietary IE javascript to something that will work cross platform. One of the changes is migrating from IE's openModalDialog's function to jQuery UI's modal dialogs.
This means I'm on a web page, in an iframe, clicking on a button that triggers "window.open" on another web page that lets a user choose options. When the user chooses an option, the index changed event fires, populating hidden text boxes in the dialog. The contents of these text boxes are supposed to be passed back to "window.opener" and into text boxes on that page.
My problem is that the code that passes these values back to the opener runs before these text boxes are on the DOM, but after the rest of the content in this page has been loaded. This seems to happen even when I use RegisterClientScriptBlock to put the javascript down the bottom of the page, after everything has loaded.
Questions:
When I am using window.opener, and the opener is in an iframe, is the opener the iframe or the document that has opened the iFrame? I think it is the former but I'm not sure
How do I wait until after the text boxes have been populated before returning their values to the opener?
Becuase I'm just passing values back to the opener, is there a better way of doing this? The code behind on the index changed function is just pulling text from the database, to be plugged into those text boxes.
Any help would be great.
To answer your second question, you should be able to use the onLoad property. Documentation here.
To give an oversimplified example of it in use:
<!doctype html>
<html>
<head>
<title>onload test</title>
<script>
function load() {
console.log("load event detected!");
}
window.onload = load;
</script>
<script>
const load = () => {
console.log("load event detected!");
}
window.onload = load;
</script>
</head>
<body>
<p>The load event fires when the document has finished loading!</p>
</body>
</html>
You might also consider using document.onLoad. Here's an explanation of the difference stolen from window.onload vs document.onload:
window.onload
By default, it is fired when the entire page loads, including its content (images, css, scripts, etc.)
In some browsers it now takes over the role of document.onload and fires when the DOM is ready as well.
document.onload
It is called when the DOM is ready which can be prior to images and other external content is loaded.
To expand further on the difference between ready and onload, the ready event occurs after the HTML document has been loaded, while the onload event occurs later, when all content (e.g. images) also has been loaded.
The onload event is a standard event in the DOM, while the ready event is specific to jQuery. The purpose of the ready event is that it should occur as early as possible after the document has loaded, so that code that adds functionality to the elements in the page doesn't have to wait for all content to load.

On page load event for single paged JavaScript applications?

I'm asking for single paged JavaScript applications where the page does not make a full request. Specifically for a site like YouTube where the initial request is a full request and everything else is a XMLHttpRequest where only the body is changing client side.
An example would be YouTube. I want to do something like this:
You go to YouTube.com and click on one of the videos.
When the video page finishes loading, console.log("page loaded");
Is there an event listener I can add for when the page loads?
No events are being fired when the DOM is modified, so it's not possible to add a listener on anything like that.
You will have to keep track of the modifications on the DOM, manually. You could add "callbacks" to the modification functions you use:
function addSomethingToPage(data){
data.doSomething():
domReady();
}
function domReady(){
//re-usable "callback"
}

Values in Google Tag Manager are undefined but in console are ok

I'm pushing values from website to Facebook through GTM, but I don't have access to make code changes on server side.
So every value that I need to send to Fb I have to find using Custom Javacripts in GTM.
I can get those values in console but I don't know why I can't see them in Debug mode. It's always undefined.
Here is one of the code in GTM:
function() {
var prod = document.getElementById("product_addtocart_form").elements.namedItem("product").value;
return prod;
}
So what am I doing wrong?
Assuming that line of code works in console, I suspect the code in your function is being fired too early and the elements aren't ready yet.
Make sure your code is not fired until the gtm.dom event is fired, if that still doesn't work then wait until gtm.load is fired. If that still doesn't work then have a look at when these elements are actually ready (maybe they're created using an AJAX call?).
If the gtm native events aren't late enough, when you know the elements are ready you should fire a custom event into your dataLayer which triggers your tags and repopulates the variables. Hopefully this will ensure your variables are populated correctly when your tags are fired.
If the elements are loaded using jQuery AJAX you should be able to bind to the ajaxComplete event on the document. See the jQuery docs. You would then fire a custom event into the data layer which would trigger the tags that using the data in the variables that should now be populated. You'd set up a trigger with type=custom event and the value being 'ajax_complete' (or whatever you call your event).
Your code would look something like this:
$(document).on('ajaxComplete', function(){
dataLayer.push({'event':'ajax_complete'});
});
If there's multiple AJAX events being fired on a single page then you'll have to write some logic to differentiate between calls and/or make sure you don't fire it multiple times. There's also a setting in tags in GTM to say 'only fire once per page load' so you could leverage that as well.

Executing external JS using innerHTML and appendChild

I've been playing around with the Material Design Lite library that Google just launched a few days ago, but have some questions, specifically on how to initiate (or execute?) external JS when the HTML changes using innerHTML and appendChild.
See the first example here. As you can see, the HTML for the menu is already within the HTML file when it is first loaded so the menu works fine.
But in this example, the HTML of the document is modified using JS. However, the menu does not work anymore because the script is not executing, I think.
How can I resolve this issue? What's a better way to achieve this result? I'm a newbie when it comes to JavaScript.
You will need to attach the proper event listener from the library. With this change (adding componentHandler.upgradeAllRegistered(); after appending the item) it should work:
document.body.appendChild(menu);
componentHandler.upgradeAllRegistered();
When the menu button is inserted dynamically (when the user clicks), it doesn't get assigned the event listeners to show the menu. I'm guessing that the material design library parses the HTML when it (the library) gets loaded (since you're loading it at the bottom of your HTML document). Since it's already loaded by the time the user clicks, it doesn't check the new element that has been inserted and can't assign it the event listeners.
If this is the case, you'll need to find a way to get the library to recognize your new button.

Categories

Resources