Best practices to load HTML + Javascript dynamically - javascript

I have a page that loads (using a XHR request) a modal box with a form inside.
The form is composed by HTML tags + some Javascript to do validation and to submit it (using another XHR request).
I did that, and it already works, but the resulting DOM is ugly, because the script tag is inside the modal, like in this simplified example:
<html>
<head>...</head>
<body>
<div id="modal">
<form>...</form> <!-- This is my dynamically loaded HTML -->
<script>...</script> <!-- This is the dynamically loaded JS -->
</div>
<script>...</script> <!-- My main scripts -->
</body>
</html>
I have two questions about this:
1) The best practice is to put all JS code right before body closes, but when I do my dynamic loading, I end up with JS inside the modal div. Is there an efficient way to load only HTML to the div and inject the JS at the end of body? Are there any tools for that? Or should I not worry about it?
2) I'm using jQuery, so I try to use $(document).ready() for all JS code, but if I use this for modal JS, it won't run, probably because the event is not triggered a second time. Is there any event I can use to make my dynamically loaded JS to run after laoding is complete? Or should I just put it in the end?

Answer to both questions:
I don't see a reason why you shouldn't insert the JS scripts in the DOM inside the modal. I think it's even better that way compared to a global place where you put all the injected scripts. This way you will still know which modal loads which script.
And it solves your second problem as well. When you first insert your DOM nodes and then the <script> element that will work on them, you don't need to wait for a ready event.
Only other way I can think of is having the modal scripts available globally, loading the modal and then doing something like ModalScript.initialize("#modal").

You could use a framework like Browserify to bundle and dynamically load ("lazy load") resources as needed.
This is a good example/tutorial.

Related

Show HTML elements on demand with JavaScript

TL;DR : I'm trying to find a way to handle HTML injections into the DOM to avoid having to include irrelevant code in the DOM at all times.
I have a large PHP application that has several forms and modals through out the pages of the application. I'm trying to find a way to lessen the DOM elements by only showing/adding elements as and when they're needed.
What I have so far looks something like this:
<body>
<!-- Page Content -->
<main>
Click to access modal
</main>
<!-- / Page Content -->
<div class="modalContainer">
<div class="modal" id="modal-login">
<!-- modal content -->
</div>
<div class="modal" id="modal-register">
<!-- modal content -->
</div>
<div class="modal" id="modal-forgotpassword">
<!-- modal content -->
</div>
</div>
</body>
In the above, when someone clicks the anchor, you'd see the appropriate modal pop-up. Once you're done with the modal, it hides away until someone needs it again.
My problem with this is that it would mean that every modal needed in the application would always be a part of the DOM regardless of whether it is needed or not.
I wanted to know if there is any way of making this process a little more dynamic? This would involve the user clicking the anchor, and the JS code injecting the Modal into the page, and when done, removing the entire modal code from the page.
I assume this would greatly improve load times and render time.
The problem is that I have been unable to understand the logic behind it, I have been doing something very similar with other parts of the project but I have not been able to apply it to the modals. Here's what I assumed would be the jQuery code for injecting the modal
$('.ismodal').click(function(event) {
event.preventDefault();
let modal = $(this).data('modal'),
elem = '#modal' + modal;
// Check if element already exists
if ($(elem).length) {
$(elem).fadeIn();
} else {
// Get element code
let elementCode = functionToGetElementCode(modal);
// Inject element
$('#modalContainer').append(elementCode);
// Fade In element
$(elem).fadeIn();
}
});
I haven't tried the above code, but I would assume something like the above should work. However, my concern is how I could code the functionToGetElementCode such that it would work, and is not terrible difficult to maintain.
I assume the easiest method would be to have the function in which we could have a switch function that would filter out the needed code. But is there a way to import the template of each modal from a folder? Something similar to the include function in PHP?
Use the <template> tag
In html there is a specific tag designed for this use, it's called <template>. You can use this tag to store your modals and then render them as needed. You're on the right track but I think there is some confusion about how loading works on the web.
JS code injecting the Modal into the page ... I assume this would greatly improve load times and render time.
When you think about load times remember the fastest thing to load is plain text. It can be extremely fast and is very very lightweight. JS, on the other hand, will need to be loaded, run, and not error out
Using AJAX (Not recommended)
If you expect the modal to be infrequently clicked, you could store it in another file and summon it via AJAX. This isn't very advantageous as it will add a network request and processing time to your modal click.
You can use AJAX calls to get the required modal.

Javascript not working on content pulled from another source

I'm pretty sure this is a dumb issue, but I searched and could not find a similar/equal scenario.
So, I have a main PHP page in which I include several Javascript files in the head section of the HTML. Then at some point I grab content (HTML + Javascript) from an outside source via file_get_contents and output it to the main page.
This new output will pick up the CSS styles from the main page normally, but any Javascript code that relies on the ones loaded at the main will not work. Even if I put the Javascript needed inside a document.ready in the main page, it will still not work.
Just to exemplify the code:
<html>
<head>
<link href="style.css" rel="stylesheet">
<script src="somejslib.js"></script>
</head>
<body>
Some HTML here generated by PHP
<?php
$content = file_get_contents('http://whatever/page');
echo $content;
?>
</body>
In the grabbed content I will have something like:
<div>
<form>
<input type="text" id="bla">
</form>
</div>
<script>$('#bla').datepicker({ somecodehere });</script>
The datepicker was included in the libs loaded in the main page, but will not work, no matter where I put this code.
Any hints?
P.S: the only way it DOES work is if I include - again - all the Javascript libs inside the new content, which of course is not a solution.
make sure you attach the listeners after the external content is loaded or use the on() event handler
http://api.jquery.com/on/
P.S. I now see your code is actually missing the document.ready and thus not waiting for the document to be loaded before executing. I'm not sure which of these applies to your actual code as you only posted an example. If you pull the content in via an ajax for example apply the first solution otherwise just wrap things up in a document ready
Solved.
Apparently it was my mistake all along. I was loading Jquery multiple times (different versions, also).
It seems that not all versions of jQuery can take care of this situation.

HTML / jQuery: How to properly include external jQuery file

I am new to JS and programming in general and hope someone can help me with this.
I am currently working on building a website where every page has its separate HTML / PHP file.
jQuery and my global / general JS functions are included in the footer of all these pages through a separate includes file "footer.php".
So far everything works as intended.
Now I have some pages that will use specific jQuery functions so I want to load the corresponding JS only if such a page is loaded.
To do this I saved the corresponding codes in separate JS files (e.g. nameOfExternalJsFile.js) and wrapped everything in there in the following:
$(document).ready(function(){
// ...
});
I then made the following updates to the corresponding PHP pages (example):
<head>
<?php
require_once("includes/header.php");
?>
<!-- here I want to include the specific jQuery functions -->
<script src="includes/js/nameOfExternalJsFile.js"></script>
</head>
<!-- ... -->
<!-- here I include the main JS functions -->
<?php require_once("includes/footer.php"); ?>
I have two concerns with this:
I am not sure if this is the right way of including such files since
I need to have them available on document ready.
I include my main JS in the footer since I was told this improves
performance but can I then include jQuery functions in the header at all ?
Can someone let me know if this is correct or if I should change anything here ?
Many thanks for any help with this.
Wrapping the functions in $(document).ready automatically takes care of this concern. From the JQuery documentation on document.ready.
A page can't be manipulated safely until the document is "ready."
jQuery detects this state of readiness for you. Code included inside
$( document ).ready() will only run once the page Document Object
Model (DOM) is ready for JavaScript code to execute.
Technically it doesn't matter whether you include the scripts in the header or the footer, as long you load JQuery first and your script second.
That said, it's generally recommended that both scripts go just before the closing body tag to increase performance as you suggested. There are some articles that discuss this like this post from performance expert Steve Souders and this guide from the Yahoo! Exceptional Performance team.
You should load the $(document).ready(...) stuff only after you have loaded jQuery, that is, in the footer file, after the jQuery <script> tag, like this :
<script src="includes/js/jQuery.min.js"></script>
<script src="includes/js/nameOfExternalJsFile.js"></script>
It`s good practise to locate all the JS files in the end of the body
<html>
<head></head>
<body>
... Some HTML
<script>SomeScripts</script>
</body>
</html>
</pre>
If you want to be sure that your external scripts are loaded after page load use:
$(function(){
/* Your code from the scripts */
});
You can change the content of footer.php to include /nameOfExternalJsFile.js manually at the bottom of the page. That´s the safest way to do it because you may load jquery before loading others scripts.

AJAX doesn't override already loaded scripts?

I'm using a version of jquery-ui-widget, 1.10.3, that works well with ajax-loaded page fragment#1 but triggers an error with page fragment#2 if fragment#2 was loaded after fragment#1.
This is strange because even if I try and override 1.10.3 with 1.8.21 when ajax-loading fragment#2 (yes I realize this is a bad hack), the code that uses the widget factory still tries to use 1.10.3 and so causes an error.
Note that this is not a problem during normal page load as 1.8.21 is outside of my ajax div id="ajax_content" and so is loaded every time.
How can I override 1.10.3 during ajax?
<html>
<div id="ajax_content">
Page fragment #1 content
<script src="jquery-ui-widget.1.10.3.js"></script>
</div
<script src="jquery-ui-widget.1.8.21.js"></script>
</html>
VS.
<html>
<div id="ajax_content">
Page fragment #2 content
<script src="jquery-ui-widget.1.8.21.js"></script>
//having this script here or not has no effect if 1.10.3 was already loaded
</div>
<script src="jquery-ui-widget.1.8.21.js"></script>
</html>
version of jquery-ui-widget won't have an effect. Rather the cause of your problem is that the script added to the innerHTML of your div id="ajax_content" will not execute.
A script added dynamically (which maybe received as a response of an ajax request or that dynamically added to the innerHTML using js or jQuery) doesn't execute. Also it is not recommended as per #Kevin B's comment. I worked around the same problem by either of the two solutions below:
Load entire script initially
Load a new page with the script in the head tag
You may disagree with the second solution here saying that the question was about the script received as a ajax response while I am suggesting you to rework your approach and use a separate page instead. This may not be appropriate to do in your scenario due to various reasons but if the only reason preventing you from doing so is that this will cause code duplication then you may explore using something like jsp:include.

Where should JS scripts go in an HTML file?

If you have JS code which is intended to run as part of loading/building the page, where in the HTML should this go? For instance modifying a <div> or adding some links.
Should this be put in the <body>, interspersed with HTML? Or should it be between the <head> and <body> elements? What order do things happen in - the order they are in the page or does HTML all happen before (non-<head>) JS is run?
If you have JS code which is intended to run as part of loading/building the page, where in the HTML should this go?
Just before the closing </body> tag is emerging as the best practice barring a specific requirement for it to be elsewhere (which there can sometimes be). It's the recommendation of the YUI folks, for instance, but it's not just them.
What order do things happen in - the order they are in the page or does HTML all happen before (non-) JS is run?
When a script tag is encountered, unless you use the defer or async attribute (and the browser supports them), all HTML parsing comes to a screeching halt and the script is downloaded and handed to the JavaScript interpreter. When the JavaScript interpreter finishes processing the script, the HTML parser can continue. It has to do this because the JavaScript can insert tokens into the HTML stream via document.write. This is also why you can load a script file and then load a second script file that relies on the first, and know that they'll get loaded in the right order. It's also why you can't access elements that are further down in the HTML stream from a script higher up in it unless you defer your code somehow (window.onload or the "DOM loaded" events many libraries support, such as jQuery's ready or Prototype's dom:loaded).
An upshot of this is that the typical practice of putting script tags in the head actually slows down the apparent load time of the page, unless those script tags need to be there for some reason. Hence the recommendation to put them just before the closing </body> tag.
There's a "gotcha" you have to watch for, though: If you have parts of the page that you want to respond to with JavaScript if the user has it enabled, loading your script at the very end leaves a brief but real race condition lying around: The user can interact with the page while your script is being downloaded. There are a variety of ways of handling that. My favorite is to detect whether JavaScript is enabled with inline script (not a separate file) in the head element and, if so, to put in a document-level handler for things where possible (you can do this with click events, for instance) which basically queues up or disables the click during that very brief period of time. That way, if JavaScript is enabled, you'll avoid the race condition, but if it isn't, any unobtrusive fallback you have in place will work.
The whole HTML file is executed in the order it is written, that means
<html>
<div id="ID"></div>
<script type="text/javascript">
document.getElementById('ID').innerHTML = "HELLO";
</script>
</html>
changes the contents of the div, wherease
<html>
<script type="text/javascript">
document.getElementById('ID').innerHTML = "HELLO";
</script>
<div id="ID"></div>
</html>
does not, because the JS code is executed before the div has loaded.
EDIT: If you want the JS to run after the page has loaded use window.onload or document.body.onload or
<body onload="...">
Alternatively if you're using a JS library such as jQuery, you can use
$(document).ready(function() {
...
});
Put them as functions in its own .js file which you include by <script src> at end of HTML <head> or <body>. If any of them needs to be executed during document load, call it using window.onload or whatever load function the JS library/framework offers, if you are using any.
As to the exact location, putting them in end of <head> allows them to be downloaded before the HTML page is been shown in browser and putting them in end of <body> allows the page to be shown a tad sooner because downloading the scripts will block the page rendering, thus it's a better speed experience.
However, IMO, it's a bit more robust to have the scripts downloaded before the page is rendered whenever you have some page elements which cannot be used without JS. In case of an impatient user this would otherwise lead to unusable elements.
I'd put it in a separate .js file and wrap the code so it is executed after the DOM is loaded. If you use a framework like jQuery or Prototype this should be easy.
For best performance place your JavaScript files at the BOTTOM of the HTML page you are serving.
To ensure that everything is set when you try to use it, execute only after the DOM is ready (there are multiple variations of this, my advice: Use a JavaScript Library).
You can put a script tag in the head, body, between the two, and more. You can put it most places but see this for a more in depth look.

Categories