'turbolinks:load' is not getting triggered on the directly loaded pages but, on the pages loaded with turbolinks 'turbolinks:load' event is working fine.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://rawgit.com/turbolinks/turbolinks/master/dist/turbolinks.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<title>
test
</title>
<script>
function loadScript(src) {
if(!document.querySelector("script[src='"+src+"']")){
var n = document.createElement("script");
n.src = src;
n.async = false;
document.getElementsByTagName("head")[0].appendChild(n);
};
};
</script>
</head>
<body>
<p style='color:red'>
Hi Priority Rendering With inline css to improve start render
</p>
<script type="text/javascript">
loadScript("dynamic_load_turbolinks_script.js");
</script>
</body>
</html>
Code of dynamic_load_turbolinks_script.js
console.log('This file will contain all functionally required script');
document.addEventListener("turbolinks:load", function() {
console.log('Inside turbolinkss Load')
});
window.onload = function(){
console.log('Inside window onload')
};
document.addEventListener('DOMContentLoaded', function(){
console.log('Inside DOMContentLoaded')
});
$(document).ready(function() {
console.log( "Inside document ready" );
});
Browser Console output of above code is
dynamic_load_turbolinks_script.js:1 This file will contain all functionally required script
dynamic_load_turbolinks_script.js:6 Inside window onload
dynamic_load_turbolinks_script.js:12 Inside document ready
I know that the issue is because dynamic scripts are executed outside of DOM parsing but, is there any way to achieve the desired behavior?
Is it possible to call a function declared in a .js file from the body of the HTML. I'm assuming the reason it won't work is because the .js file is called after the function has been called in the HTML body. Is there a way around this.
I've had a look at some answers here, but can't seem to find what I'm looking for. My apologies if it's staring at me as a beginner I may not be using the correct terminology.
jqueryfunctions.js:
function someFunction() {
// do.something;
}
index.html:
<html>
<head>
<script type="text/javascript" src="//code.jquery.com/jquery-1.8.3.js"></script>
<script src="jqueryfunctions.js"></script>
</head>
<body>
<script>
someFunction();
</script>
</body>
</html>
Here is the full/actual .js file returnedMessage() is the function I was reffering to as someFunction().
The console error I'm getting is "returnedMessage() is not defined".
$(function(){
var timer = null;
function appendmessageBox() {
$('body').append('<div id="messageBox" class="datamessagebox"> </div> ');
}
// just before body tag.
appendmessageBox();
// makes MessageBox Disappear on MouseOver
$('#messageBox').on('mouseover click', function(){
$(this).fadeOut(300);
});
function returnedMessage(message) {
if (timer) {
clearTimeout(timer); //cancel the previous timer.
timer = null;
}
$( '#messageBox' ).css('display', 'inline-block');
timer = setTimeout(function(){
$( '#messageBox' ).fadeOut( 499 );
}, 5000);
$( '#messageBox' ).append('<msg>'+message+'<br /></msg>').fadeIn( 200 );
$( '#messageBox > msg:last-of-type' ).delay(3000).fadeOut( 3000 );
setTimeout(function(){
$( '#messageBox > msg:first-of-type' ).remove();
}, 5999);
}
// This test message bellow works correctly.
returnedMessage('hello world - test 1');
});
EDIT:
you should define your function like so:
var someFunction = function() {
// do something
}
Or like so
function someFunction() {
// do something
}
But always use the function word. More information on function definition in Javascript.
More about JS file import
Javascript code is inserted between <script> tags in an HTML file
<script>
console.log("Hello World!");
</script>
You usually place those script tags inside the <head> tag. However it's recommended you put them after your <body>. This way you allow the DOM to load before you run your JS script. This is important for exemple when you want to select elements in the DOM. If you put the JS code before the actual HTML that creates this element, then JS will not find the element you would be looking for because it doesn't yet exist.
Now it's not really efficient to work with script in your HTML code so it's helpful to write JS in .js files and then import them in you HTML file like you would for a CSS file. Use the <script> to do so:
<script src="myScript.js"></script>
You can use multiple <script> tags to pull in multiple JS files. But you need to be careful of the order you write them. For instance you have a functions.js file that holds all your functions, and a menu.js that handles the menu on your application. You're using functions from the code functions.js in menu.js so you need to import the files in this order:
<script src="functions.js"></script>
<script src="menu.js"></script>
First declared, first loaded.
You can write own function like this:
Here you can see simple example: https://jsbin.com/munowupipo/edit?html,output
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Define a Function in jQuery</title>
<script src="https://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$.fn.myFunction = function() {
alert('You have successfully defined the function!');
}
$(".call-btn").click(function(){
$.fn.myFunction();
});
});
</script>
</head>
<body>
<button type="button" class="call-btn">Click Me</button>
</body>
</html>
Maybe you want to take the function on document is ready, so you must to write:
<script>
$(document).on("ready", function() { yourfunction(); });
</script>
So, lets say you have a page that wants to load from a javascript file and it includes
temp.html file
<script src="example.js"></script>
<p class="one"></p>
Now in the example.js file you have a function that is
function getInfo() {
var place = "foo"
$(".one").html(place);
}
//Edit currently I call the function inside the JS file
getInfo();
My question is how would you connect the two files so that the external javascript file knows that it is pointed to the paragraph with the class one?
Normally when this is in a single page, you would call the function and the info will be set.
I have seen a getScript method and a load method for Jquery. Would that be applicable here?
Any ideas on how to approach this? If you provide some code that will be super helpful.
Thanks in advance.
Looks like you want to execute getInfo() as soon as it's defined (i.e.: example.js is loaded).
You can try this approach:
<script src="example.js" onload="getInfo();"></script>
In your example.js, change getInfo() to something like this:
function getInfo() {
$(document).ready(function() {
var place = "foo"
$(".one").html(place);
});
}
Your language is confusing, but you could use jQuery's $(document).ready function which would suffice. Generally speaking, an externally loaded file should execute where the tag is in the script.
A hack could be to place a tag before the end of your document body, give it an id, and then use $('#id').ready() there. In general though, you could just try coding the transclusion concept (I'm guessing you're used to this) from scratch using intervals and timeouts.
<div id="rdy">
</div>
</body>
Then in your file:
$('#rdy').ready(getInfo);
Just my added opinion, you should consider that Google is up to some not-so-nice things these days, they are long-gone from the "do no evil" mantra.
If we assume you have a JavaScript file that contains this content:
function getInfo() {
var place = "foo"
$(".one").html(place);
}
then your markup will look something like this:
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="example.js"></script>
<script>
$(function(){
getInfo();
});
</script>
</head>
<body>
<p class="one"></p>
</body>
</html>
$(function(){ ... }); is just the simplified version of $(document).ready(function(){ ... });. They both more or less handle the onload event, which fires when page has finished loading.
I am having a problem where the page is loading so fast, that jquery hasn't finished loading before it is being called by a subsequent script. Is there a way to check for the existence of jquery and if it doesn't exist, wait for a moment and then try again?
In response to the answers/comments below, I am posting some of the markup.
The situation... asp.net masterpage and childpage.
In the masterpage, I have a reference to jquery.
Then in the content page, I have a reference to the page-specific script.
When the page specific script is being loaded, it complains that "$ is undefined".
I put alerts at several points in the markup to see the order in which things were firing, and confirmed that it fires in this order:
Master page header.
Child page content block 1 (located inside the
head of the masterpage, but after the masterpage scripts are
called).
Child page content block 2.
Here is the markup at the top of the masterpage:
<%# Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="SiteMaster" %>
<!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">
<head id="Head1" runat="server">
<title>Reporting Portal</title>
<link href="~/Styles/site.css" rel="stylesheet" type="text/css" />
<link href="~/Styles/red/red.css" rel="stylesheet" type="text/css" />
<script type="text/Scripts" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/Scripts" language="javascript" src="../Scripts/jquery.dropdownPlain.js"></script>
<script type="text/Scripts" language="javascript" src="../Scripts/facebox.js"></script>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
Then in the body of the masterpage, there is an additional ContentPlaceHolder:
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
In the child page, it looks like so:
<%# Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Dashboard.aspx.cs" Inherits="Data.Dashboard" %>
<%# Register src="../userControls/ucDropdownMenu.ascx" tagname="ucDropdownMenu" tagprefix="uc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<link rel="stylesheet" type="text/css" href="../Styles/paserMap.css" />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
***CONTENT HERE***
<script src="../Scripts/Dashboard.js" type="text/javascript"></script>
</asp:Content>
Here is the content of the "../Script/Dashboard.js" file:
$(document).ready(function () {
$('.tgl:first').show(); // Show the first div
//Description: East panel parent tab navigation
$('.tabNav label').click(function () {
$('.tabNav li').removeClass('active')
$(this).parent().addClass('active');
var index = $(this).parent('li').index();
var divToggle = $('.ui-layout-content').children('div.tgl');
//hide all subToggle divs
divToggle.hide();
divToggle.eq(index).show();
});
});
Late to the party, and similar to Briguy37's question, but for future reference I use the following method and pass in the functions I want to defer until jQuery is loaded:
function defer(method) {
if (window.jQuery) {
method();
} else {
setTimeout(function() { defer(method) }, 50);
}
}
It will recursively call the defer method every 50ms until window.jQuery exists at which time it exits and calls method()
An example with an anonymous function:
defer(function () {
alert("jQuery is now loaded");
});
the easiest and safest way is to use something like this:
var waitForJQuery = setInterval(function () {
if (typeof $ != 'undefined') {
// place your code here.
clearInterval(waitForJQuery);
}
}, 10);
you can use the defer attribute to load the script at the really end.
<script type='text/javascript' src='myscript.js' defer='defer'></script>
but normally loading your script in correct order should do the trick, so be sure to place jquery inclusion before your own script
If your code is in the page and not in a separate js file so you have to execute your script only after the document is ready and encapsulating your code like this should work too:
$(function(){
//here goes your code
});
Yet another way to do this, although Darbio's defer method is more flexible.
(function() {
var nTimer = setInterval(function() {
if (window.jQuery) {
// Do something with jQuery
clearInterval(nTimer);
}
}, 100);
})();
You can try onload event. It raised when all scripts has been loaded :
window.onload = function () {
//jquery ready for use here
}
But keep in mind, that you may override others scripts where window.onload using.
I have found that suggested solution only works while minding asynchronous code. Here is the version that would work in either case:
document.addEventListener('DOMContentLoaded', function load() {
if (!window.jQuery) return setTimeout(load, 50);
//your synchronous or asynchronous jQuery-related code
}, false);
edit
Could you try the correct type for your script tags?
I see you use text/Scripts, which is not the right mimetype for javascript.
Use this:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript" src="../Scripts/jquery.dropdownPlain.js"></script>
<script type="text/javascript" src="../Scripts/facebox.js"></script>
end edit
or you could take a look at require.js which is a loader for your javascript code.
depending on your project, this could however be a bit overkill
Use:
$(document).ready(function() {
// put all your jQuery goodness in here.
});
Check out this for more info: http://www.learningjquery.com/2006/09/introducing-document-ready
Note: This should work as long as the script import for your JQuery library is above this call.
Update:
If for some reason your code is not loading synchronously (which I have never run into, but apparently may be possible from the comment below should not happen), you could code it like the following.
function yourFunctionToRun(){
//Your JQuery goodness here
}
function runYourFunctionWhenJQueryIsLoaded() {
if (window.$){
//possibly some other JQuery checks to make sure that everything is loaded here
yourFunctionToRun();
} else {
setTimeout(runYourFunctionWhenJQueryIsLoaded, 50);
}
}
runYourFunctionWhenJQueryIsLoaded();
It's a common issue, imagine you use a cool PHP templating engine, so you have your base layout:
HEADER
BODY ==> dynamic CONTENT/PAGE
FOOTER
And of course, you read somewhere it's better to load Javascript at the bottom of the page, so your dynamic content doesnot know who is jQuery (or the $).
Also you read somewhere it's good to inline small Javascript, so imagine you need jQuery in a page, baboom, $ is not defined (.. yet ^^).
I love the solution Facebook provides
window.fbAsyncInit = function() { alert('FB is ready !'); }
So as a lazy programmer (I should say a good programmer ^^), you can use an equivalent (within your page):
window.jqReady = function() {}
And add at the bottom of your layout, after jQuery include
if (window.hasOwnProperty('jqReady')) $(function() {window.jqReady();});
Rather than "wait" (which is usually done using setTimeout), you could also use the defining of the jQuery object in the window itself as a hook to execute your code that relies on it. This is achievable through a property definition, defined using Object.defineProperty.
(function(){
var _jQuery;
Object.defineProperty(window, 'jQuery', {
get: function() { return _jQuery; },
set: function($) {
_jQuery = $;
// put code or call to function that uses jQuery here
}
});
})();
I'm not super fond of the interval thingies. When I want to defer jquery, or anything actually, it usually goes something like this.
Start with:
<html>
<head>
<script>var $d=[];var $=(n)=>{$d.push(n)}</script>
</head>
Then:
<body>
<div id="thediv"></div>
<script>
$(function(){
$('#thediv').html('thecode');
});
</script>
<script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
Then finally:
<script>for(var f in $d){$d[f]();}</script>
</body>
<html>
Or the less mind-boggling version:
<script>var def=[];function defer(n){def.push(n)}</script>
<script>
defer(function(){
$('#thediv').html('thecode');
});
</script>
<script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<script>for(var f in def){def[f]();}</script>
And in the case of async you could execute the pushed functions on jquery onload.
<script async onload="for(var f in def){def[f]();}"
src="jquery.min.js" type="text/javascript"></script>
Alternatively:
function loadscript(src, callback){
var script = document.createElement('script');
script.src = src
script.async = true;
script.onload = callback;
document.body.appendChild(script);
};
loadscript("jquery.min", function(){for(var f in def){def[f]();}});
Let's expand defer() from Dario to be more reusable.
function defer(toWaitFor, method) {
if (window[toWaitFor]) {
method();
} else {
setTimeout(function () { defer(toWaitFor, method) }, 50);
}
}
Which is then run:
function waitFor() {
defer('jQuery', () => {console.log('jq done')});
defer('utag', () => {console.log('utag done')});
}
I don't think that's your problem. Script loading is synchronous by default, so unless you're using the defer attribute or loading jQuery itself via another AJAX request, your problem is probably something more like a 404. Can you show your markup, and let us know if you see anything suspicious in firebug or web inspector?
Check this:
https://jsfiddle.net/neohunter/ey2pqt5z/
It will create a fake jQuery object, that allows you to use the onload methods of jquery, and they will be executed as soon as jquery is loaded.
It's not perfect.
// This have to be on <HEAD> preferibly inline
var delayed_jquery = [];
jQuery = function() {
if (typeof arguments[0] == "function") {
jQuery(document).ready(arguments[0]);
} else {
return {
ready: function(fn) {
console.log("registering function");
delayed_jquery.push(fn);
}
}
}
};
$ = jQuery;
var waitForLoad = function() {
if (typeof jQuery.fn != "undefined") {
console.log("jquery loaded!!!");
for (k in delayed_jquery) {
delayed_jquery[k]();
}
} else {
console.log("jquery not loaded..");
window.setTimeout(waitForLoad, 500);
}
};
window.setTimeout(waitForLoad, 500);
// end
// now lets use jQuery (the fake version)
jQuery(document).ready(function() {
alert('Jquery now exists!');
});
jQuery(function() {
alert('Jquery now exists, this is using an alternative call');
})
// And lets load the real jquery after 3 seconds..
window.setTimeout(function() {
var newscript = document.createElement('script');
newscript.type = 'text/javascript';
newscript.async = true;
newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(newscript);
}, 3000);
A tangential note on the approaches here that load use setTimeout or setInterval. In those cases it's possible that when your check runs again, the DOM will already have loaded, and the browser's DOMContentLoaded event will have been fired, so you can't detect that event reliably using these approaches. What I found is that jQuery's ready still works, though, so you can embed your usual
jQuery(document).ready(function ($) { ... }
inside your setTimeout or setInterval and everything should work as normal.
How can I use Jasmine or other tool to test the JavaScript / JQuery that is embedded inside a web page like in the example below?
<html>
<head>
<!-- usual includes -->
</head>
<body>
<span id="myspan1"></span>
<span id="myspan2"></span>
<script type="text/javascript">
$(document).ready(function(){
$('#myspan1').html('something');
$('#myspan1').click(function(){
$('#myspan1').html('something else');
});
doStuff();
function doStuff() {
$('#myspan2').html('stuff done');
}
});
</script>
</body>
</html>
I simply assume that you want to ensure that the "stuff done" appears on the page after a reasonable amount of time.
describe("My page", function () {
it("should say stuff done after max 500 ms", function () {
waits(function () {
return $('#myspan2').html() == 'stuff done';
}, 500);
});
});
http://jsfiddle.net/ahus1/QP2Pk/
Normally you would put your javascript code into a external file.
Then you can setup a test page that includes the minimum elements from the normal page, plus Jasmine.
In this test page I didn't wait to run Jasmine when the page was finally loaded, but works anyway.
Br Alexander.