Loading elements with javascript then applying them javascript - javascript

I am trying to load "header.html" using jquery .load("file") function, apply css to the loaded elements (works) and then apply JS to the loaded elements, functions like floating menu on scroll, etc, this it not working however. This is the order I import the files in the head:
<!-- Elements going to be loaded are using this font-awesome css
so they must be loaded before anything -->
<link rel="stylesheet" href="awesome/css/font-awesome.min.css" />
<!-- Then importing the jquery -->
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<!-- This is the point where i load the header.html -->
<script src="js/indexLoad.js"></script>
<!-- Then apply css to the loaded elements (works) -->
<link rel="stylesheet" href="css/index.css" />
<!-- Then apply JS to the loaded elements (doesnt work) -->
<script src="js/index.js"></script>
Inside the header.html I import some elements like nav for example.
Then changing style to nav to display it in red.
When I use var newHeight = $("nav").position().top in the index.js I just get cannot read property value of null... Why did css apply styles to the loaded element and JS coudnt get em?
I properly use $(document).ready( function(){} in both .js files:
indexLoad.js
$(document).ready( function(){
$("header").load("http://localhost/js/header.html");
});
index.js
$(document).ready( function(){
var newHeight = $("nav").position().top;
});

ALWAYS first load all the CSS files, and then the JS scripts. Always.
And all the JS that accesses DOM elements needs to be loaded after the DOM is ready. Either by using one of the handlers (like $(document).ready) or simply putting the script at the very end of the HTML body. (not sure if you were doing that to all the scripts, you probably are)
Since you're using an AJAX call to load the header, you need to wait for it to load in order for the nav element to be available to JS. So use the load() callback function to execute everything that manipulates the header markup.
Key stuff: And since you're loading index.js and indexLoad.js separately, you actually need some kind of coordination between them. I suggest setting up an event listener in the index.js file, and firing that event in the indexLoad.js once the header is ready (in the load() callback). Something like this:
indexLoad.js
$(document).ready( function(){
$("header").load("http://localhost/js/header.html", function() {
$('body').trigger('headerReady');
});
});
index.js
$('body').on('headerReady', function(){
var newHeight = $("nav").position().top;
// everything else that requires header elements goes here
// or under a similar listener
});
Here is a simple snipper that mimics this using a timeout to simulate the async call delay:
setTimeout(function(){
$('body').append('<nav>Nav here</nav>');
$('body').trigger('headerReady'); // simulating a 3s delay
}, 3000);
$('body').on('headerReady', function() {
alert('header is ready');
$('nav').css('color', 'green');
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

JS is asynchronous, and therefore even if the newHeight measurement is made further down the page, it does not mean that it will be executed/run after the loading has completed. Instead, use callbacks:
$(document).ready( function(){
$("header").load("http://localhost/js/header.html", function() {
var newHeight = $("nav").position().top;
});
});
... or deferred objects: Using jQuery load with promises

Related

Load Multiple js file after page load

I have multiple JavaScript files which are loaded before page load which are affecting page speed. I want that my JS files to load after page load though to improve page speed.
I tried to use async and defer but due to dependency to each other, this way is not working out for me. I also tried lazy loading through AJAX but that is also not working for me (using this link https://w3bits.com/async-javascript)
#section Scripts {
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=API_KEY&sensor=false&libraries=places"></script>
<script src="/lib/bootstrap-datetimepicker/js/moment.js" type="text/javascript"></script>
<script src="/lib/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js" type="text/javascript"></script>
<script src="/js/viewcomponent/windowsignup.js"></script>
<script type='text/javascript' src='/js/viewcomponent/kundliregistrationwindow.js' async='async'></script>
}
I use multiple JS files on a page and I want them all to load after page load. Is there any way to do that?
You can use getScript inside document.ready.
$(document).ready(function() {
$.getScript("domainpath/lib/bootstrap-datetimepicker/js/moment.js");
});
It's fetch your js after dom ready.
You can use Jquery's $.getScript() function but then you have to keep an eye on proper loading order. Would recommend more to bundle all necessary files on the server side and only serve a single file
When the browser receives a request for an HTML file the DOM starts to draw. If you place your scripts in the <head> tag the DOM stops from rendering and the browser starts to execute the <script> files.
One solution could be to place your <script> files at the end of the <body>.
Another solution could be to dynamically load your scripts into your page after the page is loaded like this:
window.addEventListener('load', () => {
let script = document.createElement('script');
script.src = './my_lazy_loaded_script.js';
document.body.appendChild(script);
});
If you have multiple files that are dependent on each other you could do something like this using the async/await mechanism:
window.addEventListener('load', async () => {
console.log('page loaded')
try{
await loadFileAsync('./my_first_lazy_load.js');
await loadFileAsync('./my_second_lazy_load.js');
} catch(err){
console.log(err);
} finally {
console.log('Everything loaded')
}
})
const loadFileAsync = (url) => {
return new Promise((resolve, reject) => {
if(url){
let script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
resolve(true);
} else {
reject(false);
}
});
}
If you want to load your scripts as soon as the DOM is rendered, you can replace window.addEventListener('load',()=>{}) with document.addEventListener('DOMContentLoaded', () => {})
You usually use a Scripts section to control the location where your scripts are being rendered in the document. The way browsers work, they will interpret the HTML from top to bottom. If they encounter a <script> tag, they will pause the HTML rendering and interpret the JavaScript first. For external JavaScript files this means that they will be included and interpreted first (if they aren’t marked as defer or async).
As such, a common practice is to add JavaScript at the end of the <body> tag. That way, the scripts will not prevent rendering the document first but they will also execute early enough to be able to immediately have an effect. In addition, since they are executed after the majority of the <body> has already been interpreted, they can directly access DOM elements. So you generally don’t need to listen to another DOM event first before you can do something with the DOM.
For example, this would work just fine:
<body>
<div id="foo"></div>
<script>
var foo = document.getElementById('foo');
</script>
</body>
However, if you had the <script> before the <div> (or inside of the <head>), the script would fail to find the foo element simply because it isn’t added to the DOM yet.
For ASP.NET Core this means that you should make sure that your Scripts section is added at the end of your <body> tag inside your layouts file. So it should look like this:
<!-- (The rest of the layout) -->
#RenderSection("Scripts", required: false)
</body>
</html>
You can also add script tags before the RenderSection call to make sure that those scripts are available on all pages but loaded before other scripts. For example, if you are using Bootstrap and you want to use jQuery, it might make sense to include that globally for all pages. But since you have it before the other scripts, it is available for the other scripts.
As far as dependencies between scripts go, make sure that you include the scripts in the order they need to executed. So if you have script B that depends on functions in script A, make sure to include A before B. But then, without using defer or async, just including them should work just fine.

Jquery not working inside of .net project

I have this script referenced inside my main.master file:
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.0.min.js" type="text/javascript"></script>
and inside of my Web User Control I have this jquery but it isnt working, i cant really see where there would be a problem. My code works just fine inside of jsfiddle:
<script type="text/javascript">
$(".package-container").click(function () {
$(this).closest('.radio-group-row').find('.package-title').removeClass('highlight');
$(this).find('input:radio').prop('checked', true);
$(this).find('.package-title').addClass('highlight');
});
</script>
EDIT
My jquery is referenced near the bottom of my master page above the closing body tag.
Make sure your jQuery include is placed early on the page (HEAD element) and either place your code at the end of the body element or wrap it in a DOM ready handler like this:
<script type="text/javascript">
$(function(){
$(".package-container").click(function () {
$(this).closest('.radio-group-row').find('.package-title').removeClass('highlight');
$(this).find('input:radio').prop('checked', true);
$(this).find('.package-title').addClass('highlight');
});
});
</script>
$(function(){YOUR CODE HERE}); is a shortcut for $(document).ready(function(){YOUR CODE HERE});
The advantage of using DOM ready handlers, is that you can place the jQuery code anywhere (including injection by child views/controls).
Update:
If you also need to locally scope your $ variable, I suggest using this rather nice shortcut DOM ready handler. It passes the jQuery instance as a first parameter to the DOM ready function you provide:
jQuery(function($){
// Your code placed here can use $ without any worry about other packages!
});

Separating JQuery Scripts with Selectors in External file does not work?

I have a JQuery Selector and an event associates with it.I want to keep it in external file and just copy and directly save it. The thing which I see is that the external JavaScript that has the selector does not work. Can someone explain Why?
NOTE: I am able to use the same function within my HTML file but when externalize it. It just doesn't work .
The script that I have is as follows:-
$('#pervious').click(function() {
var presentSlide = $('.visible').attr('id');
var tempArr = presentSlide.split("-");
var persentSlideNo = tempArr[1];
var perviousSlideNo = Number(persentSlideNo) - 1; if (perviousSlideNo > -1)
{
var perviousSlide = "Slide-" + perviousSlideNo;
$('#' + presentSlide).fadeOut('slow',function(){
$(this).removeClass('visible').addClass('hidden');
});
$('#' + perviousSlide).fadeIn('slow',function(){
$(this).removeClass('hidden').addClass('visible');
});
}
});
How are you including this script?
Note that it needs to go below the definition of your id=pervious element, or it needs to go after it (e.g. document.ready), otherwise the element won't exist, and there won't be anything to bind to.
UPDATE
To restate, it needs to execute AFTER the pervious element gets created. Putting it in an external document is likely causing it to execute BEFORE the pervious HTML element is created, and therefore it doesn't work. You can put it in an external file, sure, just make certain that the element gets loaded, e.g.
$(document).ready(function() {
$.getScript('http://yoursite.com/extrascript.js');
});
After you have determined you are actually linking to it by doing an alert, wrap your code like so:
$(function(){
// place your code inside here for ready event
});
What you are doing is running your selector before the document is ready. The selector runs before the dom is there and there is no results in the selector so you don't attach anything.
You have to include scripts with the form of: (including the closure tag as such)
<script src="myexternal.js" type="text/javascript"></script>
Not any of these:
<script src="myexternal.js" type="text/javascript" />
<script src="myexternal.js" />
<script src="myexternal.js" ></script>
form or it will not always get rendered properly and thus not execute.
and of course, since you are using jQuery, you should put YOUR code AFTER the jQuery library link AND include your code in a document ready as others have demonstrated.

jQuery not working in external JavaScript

I am new to jQuery and am stuck at some strange issue. I am using jQuery's change and click methods. They are working fine when used in my HTML file in the <script> tag.
Like:
<script>
$("select,input").change(function ()
{
// My code and some alerts
});
</script>
When I copied the same in external JavaScript code without <script> and imported that in my HTML it was not at all working.
Are there any changes which are needed to use jQuery in external JavaScript code?
PS: Some other non-jQuery functions present in same external JavaScript code are successfully called from HTML.
First off, you don't want a <script> tag in an external JavaScript file, if that's how I'm reading your post.
The trick with jQuery is that your code is set to execute immediately.
You want to wrap your script so that it loads when the document is ready, in something like:
$(document).ready(function(){
$("select,input").change(function ()
{
// My code and some alerts
})
});
And you want to make sure that your file is loaded after jQuery (otherwise the $ global will not be set).
Additions:
Here is what your HTML should look like:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="jscript/myExternalJs.js"></script>
Here is what your JavaScript code should look like (note there is no script tag inside the JavaScript file):
$(document).ready(function(){
$("select,input").change(function ()
{
// My code and some alerts
})
// Other event handlers.
});
As far as your other script... it sort of depends on what you're doing. The most important thing is to not try to hook event listeners up to objects that don't yet exist, which is why we use document.ready.
Did you make sure jquery is defined before your own jquery code?
You should also make sure the DOM is ready when dealing with jquery:
$(document).ready(function() {
$("select,input").change(function() {
// my code and some alerts
});
// more code here if needed, etc.
});

using jQuery (put at the bottom of the page) on specific page

Because of performance purposes I put loading of jQuery scripts at the bottom of the page (just before the closing body tag).
My question is how to enable page specific scripts? I don't want to put everything inside $(document).ready method (again because of performance purposes).
Update: I'm using a template system so I put jQuery loading in the template. That way jQuery calls don't get recognized even if I put them at the end of a specific page because jQuery is not loaded at that point.
I'm not 100% sure what you're asking, but if it's what I think it is, the answer is that you can't have your cake and eat it too.
It seems that you've moved jQuery to the button of the page but have some elements of the page that you want to use JavaScript on, but don't want to wait for document.ready for all of the? Maybe something like the following?
<html>
<body>
<ul id="maybe-some-menu-that-needs-js-initialization-for-example">
...
</ul>
<script>
/* javascript goes here that uses jquery for the above menu (or whatever)
AND you don't want to wait for document.ready for this to happen */
</script>
...
<script src="including jquery here"></script>
<script src="including other scripts here"></script>
</body>
</html>
If that's the case, then refer to what I said from the get-go. You'll have to move jQuery (at least the library, not necessarily all your other JavaScript) back to the top of the page. Either that or don't us jQuery for the things you don't want to wait for document.ready for.
Edit: If you want to perform actions based on the page that you are, then there are two methods, each better and more preferable then the last.
Use location.pathname to determine what functionality you need.
Organize your JavaScript into separate, modular files by their functionality and include only those that are needed for the specific page.
The $(document).ready() will not be overridden when using it more than once, so you can load 2 script files that both adds functionality to be run when the document is loaded.
using $(document).ready, it doesn't matter where in the page it is, as it will only execute when the DOM has finished loading. The only code that should go inside $(document).ready is code that needs to be set up when the DOM has loaded, e.g. event handlers, any effects/animations that you want to run as soon as the DOM has finished loading, etc. Other functions do not need to be in $(document).ready, such as a function used in sorting an array, named functions called when events are raised, etc.
As has been pointed out, you can have more than one $(document).ready function on a page, as what you are doing is specifying a function (named or anonymous) to execute when the ready event (a jQuery event) is raised.
EDIT:
That article that you have linked to in the comments on this answer provides and example of what you are trying to achieve. As an example, you would have a JavaScript file with the following setup to declare a global variable
var myPageLibrary = {
homePage : {
init : function() {
$(document).ready(function() {
/* page specific functions that need to run,
for exmaple, binding event handlers, etc */
});
}
},
aboutPage : {
init : function() {
$(document).ready(function() {
/* page specific functions that need to run,
for exmaple, binding event handlers, etc */
});
}
}
}
/* you might have functions here that are bound to events.
Here is an example */
function showSubMenu(e) {
$(e.target).next('div').show();
}
function hideSubMenu(e) {
$(e.target).next('div').hide();
}
Then in your pages, you would have the following structure (this example uses the home page)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>This is my Home Page</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="path-to-myPageLibrary.js"></script>
<script type="text/javascript">
myPageLibrary.homePage.init();
</script>
</head>
<body>
<!-- Page content -->
</body>
</html>
with jQuery script file referenced first, followed by myPageLibrary script file, followed by the script block calling myPageLibrary.homePage.init();
If I understand correctly, you need to put some javascript code that calls jquery in the middle of your page. But your jquery include is at the bottom of the body. You can do this by calling the jquery at the window.load event. This event fires after all async scripts have loaded and executed. e.g.:
<body>
<script>
$("#myElem").val(); // fails, "$" not defined
window.addEventListener("load", function(evt) {
$("#myElem").val(); // ok, jquery is loaded
});
</script>
<span id="myElem>hi</span>
<script src="//cdn.jquery.com"></script>
</body>
This allows you to call jQuery plugin methods in the body and load jQuery plugin on to bottom of the page headjs
Just have a page-specific $(document).ready().
Have you tried "#section script"? It will automatic add the codes at the end of the page, thus you can have page specific jQuery scripts.
#section scripts {
<script>
jQuery(document).ready(function () {
//put your jQuery codes here
});
</script>
}
As I understand your issue:
jQuery is not available on the page before it loads.
You use templates and each has it's own js code to run when page loads
You want them to run with jQuery.
If I got you right, here is the solution:
In <head> define global task array:
...
<script>
const JQUERY_READY_TASKS = []
</script>
</head>
After you load jQuery and other scripts define:
...
<script>
jQuery(document).ready(() => {
// Execute all tasks added by templates
for (let n=0; n<JQUERY_READY_TASKS.length; n++)
JQUERY_READY_TASKS[n](jQuery)
}
});
</script>
</body>
Wrap initialization code of your templates in functions:
...
<script>
// Within template
JQUERY_READY_TASKS.push(($) => {
// Template init code
// You can use $ as jquery here
})
</script>
...

Categories