How to make sure that a javascript function is called first? - javascript

I am working on a SaaS platform. I do not have access to the app.js file. However, I am able to upload my own JS in the footer. Currently, I have a function that on click tests to see if the menu is open by checking if the main wrapper has a class of menu-active. One of two things happen, if the menu is active I remove the overlay and if it is not I add a class of overlay. Unfortunately, the app.js, which I do not have access, uses toggleClass removes the menu-active class for CSS. Occasionally, the app.js removes the class which I am checking first and messes up my function. However, most of the time it works. How can I make my function click called first 100% of the time? I am using JQuery 2.1.1
$(".menu-toggle").first().click(function () {
if (!$("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").addClass("overlay");
}
if ($("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").removeClass("overlay");
}
});

You could wrapping the check in a setTimeout:
$(".menu-toggle").first().click(function () {
setTimeout(function() {
if (!$("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").addClass("overlay");
}
if ($("#wrapper").hasClass("menu-active")) {
$("#wrapper").find("div:first").removeClass("overlay");
}
}, 1);
});
That should cause the check to happen after the browser has updated the DOM.

Make the following,
<link rel="preload" href="path-to-your-script.js" as="script">
<script>
var scriptPriority =
document.createElement('script');
scriptPriority.src = 'path-to-your-script.js';
document.body.appendChild(scriptPriority);
</script>
About: Link rel Preload
Link rel preload is method that is used by a few developers, its something that almost nobody known and its use to give priority to a script or link css.
More info in:
https://developers.google.com/web/updates/2016/03/link-rel-preload
https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content

Related

JS class change script? (Working in JS Fiddle)

JS noob here looking for some help. I've written something extremely basic in able to change a class which would hide a page element. The hide class just has a display none.
I've got it working fine in JS fiddle but when replicating it on my site, nothing happens? What am I doing wrong?
JS Fiddle - https://jsfiddle.net/MattPremier/x8rmn4cb/2/
<script type="text/javascript">
window.onload = function () {
var bookShow = "No";
if (bookShow == "No") {
// execute this code
document.getElementById('booking-show').classList.add('hide-widget');
}
else {
// execute this code
document.getElementById('booking-show').classList.add('show-widget');
}
};
</script>
<div id="booking-show" class="show-widget"><p>WORKING?</p></div>
I would recommend checking your CSS to make sure that the display isn’t otherwise set unless you need it to be set then inside the hide-widget CSS class put:
“display: none !important;”
And also remove show-widget from the object at the bottom as it might be conflicting with CSS.
Note Sorry for the bad formatting of this message as I’m on my cell phone.

How to add a js function to ONSEN page load? (monaca)

I would like an animation to autostart on page load. I'm in the Onsen UI V2 JS Splitter example within the ons-template in an ons-page.
I found that adding a script tag between the "/ons-page" and the "/ons-template" tags gets read (this took me quite some time... (-; )
I followed the guide
<script>
document.addEventListener("init", function(event) {
if (event.target.id == "score.html") {
Progress1();
}
}, false);
</script>
But nothing happened.
I changed it to:
.... html stuff
</ons-page>
<script>
$(document).ready(function() {Progress1()});
</script>
</ons-template>
But now it cannot find a component from the HTML file and it says
Uncaught Error: container does noet exist #container1 www/lib/jquery-3.1.0.slim.min.js:2
What can i do? I solved it now with a button. That proves it works, but is of course no auto start.
Any ideas...?
thanks
I see this one is old, but anyway.
Onsen UI documentation says:
There are several events you can listen to. 'init' or 'show' will do the trick. Make sure you load the script as an external file, not inline script. Cordova templates are added and removed on navigation. Inline script is not efficient at all
document.addEventListener('init', function(event) {
if (event.target.matches('#yourpage')) {
ons.notification.alert('Page is initiated.');
// Set up content...
}
}, false);
This doesn't look a good way to achieve your goal. You should use Cordova Events or, if you need to wait for Onsen to be loaded, ons.ready function. Here is an example:
<script>
ons.ready(function() {
//execute your code
});
</script>
Hope it helps!
With a lot of help, this is a solution that works. It is an interval that checks if the container 'exists'. It repeats until the container is there and then it calls the function. In the function the interval is cleared (so it stops checking).
See also here: http://www.w3schools.com/js/js_timing.asp
var tryForContainer;
function progression1Test(){
tryForContainer = setInterval(checkIfContainerIsReady, 100);
}
function checkIfContainerIsReady(){
//alert(document.getElementById('container1'));
if(document.getElementById('container1') !== null){
Progress1();
}
}

JavaScript terminate script without throw error

I have site with AJAX navigation.
main.js handle AJAX navigation and few another tasks.
Some of my subpages require own scripts, lets take gallery for example.
In main.js i have function which loads gallery content and gallery.js (gallery.js is just added to head tag).
Everything works fine until i leave gallery and enter gallery again. As result i have two gallery.js working which ruin down everything.
I tried:
remove <script type="text/javascript" src="js/gallery.js"></script> on gallery leave but this doesn't change anything
use throw but it terminate both gallery.js and main.js, so AJAX navigation die
There is way to terminate/stop gallery.js without terminate main.js?
That's actually more about code architecture than anything else.
Your code really should look like this
function loadGalleryFor(element) {
var active = true;
// async load here while active == true
return {
stop:function() { active = false; }
loading:function() { return active; }
};
}
And you call it as:
var galleryCtl = loadGalleryFor(...);
and when you need you can stop it simply as:
galleryCtl.stop();
Based on the code in your comment, first check to see if the gallery script is already in the head section:
if ($("head>script[src='gallery.js']").length === 0) {
$("head").append("<script src='gallery.js'></script>");
}

"$" is undefined; jquery clearly linked to in <head>; no conflicting scripts or libraries

-=- THIS CODE FUNCTIONS. I AM LEFT TO ASSUME THERE WAS A PROBLEM WITH THE CACHE AS NOTHING HAS BEEN ALTERED BETWEEN NON-FUNCTION/FUNCTION. THANK YOU ALL FOR YOUR HELP (especially Niko who got the ball rolling and helped me form a richer understanding of jquery syntax) -=-
I've written this script by hand, and finally decided to update it to jquery in a bid to get used to that, and streamline the code. This is supposed to render a simple menu (which it did before).
Both .js files are in the same directory as the .html file. This is being tested on my pc, not on a server.
A previous version of this code worked perfectly just linking to taskMaster.js. At that point my code didn't use "$" tagged calls.
Firebug is displaying an error of "ReferenceError: $ is not defined" when it tries to call $(document).ready(function () {
the "net" tab doesn't display either .js files as being loaded; the net tab is completely empty and shows no activity - I believe this is because I'm testing this off my PC; the net panel is empty when I load the functioning code
I've reinstalled a fresh version of jquery on the offchance there was something wrong, to no avail
Broken code "taskMaster.js":
$(document).ready(function () {
//main menu
function Main()
{
var mainList = ["New List","Show Lists","Delete Lists"];
//var onClick = [New,Lists,Delete];
var mainMenu = new Menu("Main Menu","menuMain",mainList/*,null*/);
mainMenu.contentMenu();
}
$(Main);
//menu class
function Menu(name,divClass,content/*,onclick*/)
{
$("#interface").html(null);
//title
formatDiv("interface",name,divClass,name/*,null*/);
//return
if(name != "Main Menu")
{
formatDiv(name,null,"return","^ Main Menu","Main()");
}
//display options
this.contentMenu = function()
{
for(i=0; i<content.length; i++)
{
formatDiv("interface",content+i,"menuContent",content[i]/*,onclick[i]*/);
}
}
}
//format divs
function formatDiv(target,divId,divClass,content/*,onclick*/)
{
$("#"+target).append("<div id=\'" + divId + "\' class=\'" + divClass + "\'>" + content +"</div>");
/*$("#"+divId).click(function()
{
onclick;
});*/
}
});
I commented out unused lines, but it's showing "$" as undefined
Here is the HTML:
<html>
<head>
<script type="text/javascript" src="jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="taskMaster.js"></script>
<link rel="stylesheet" type="text/css" href="taskMaster.css" />
</head>
<body>
<div id="interface">
</div>
</body>
</html>
As far as I can tell there is nothing wrong with this html - the same format worked perfectly fine before. All that's changed is that I've introduced jquery and changed some commands in taskMaster.js to use "$".
Okay, I'm now posting this as an answer, because it is easier to provide some examples here.
First thing is: Whenever you do an operation that accesses the DOM, such as $("#interface").html(null);, you will first need to make sure that the DOM is ready. This is what the "ready" event is for:
$(document).ready(function() {
/* The code here is executed when the DOM is ready! */
});
So if "Main()" is a function that kicks everything off, you can simply list it to be called when the DOM is ready:
function Main() {
/* ... */
}
$(document).ready(Main);
Most the time it is also safe to encapsulate the entire JavaScript code in a "ready" event handler:
$(document).ready(function() {
function Main() { /* ... */ }
function formatDiv(...) { }
// ...
// All functions are defined, now let's go:
Main();
});
Now the click handlers: jQuery's "click()" function expects a function that is to be called when the corresponding DOM elements gets clicked on. You're currently passing strings like "New()" to it, but you should directly pass the functions. To do so, alter the code in "Main()" this way:
// Old: var onClick = ["New()","Lists()","Delete()"];
var onClick = [New, Lists, Delete]; // New
This adds the actual functions to the array, not just their names.

jQuery event that triggers after CSS is loaded?

I have a couple of links on my page (inside a <div id="theme-selector">) which allow you to change the CSS stylesheets:
$('#theme-selector a').click(function(){
var path = $(this).attr('href');
$('head link').remove();
$('head').append('<link type="text/css" href="'+path+'" rel="stylesheet" />');
return false;
});
Now, after I've changed the style on the page, I want to get the new background color, using the following code (which I put after the $('head').append call):
var bgcolor = $('body').css('background-color');
alert(bgcolor);
The problem is, I think, that it takes some time for the browser to download the new stylesheet and I sometimes get the old background color in my alert message. Is there some event I can bind that will only alert me after all the stylesheets are loaded on the page?
At the moment, all I can think of is using a setTimeout(function(){}, 5000); which isn't great, because what if it takes longer/shorter to load all the CSS on the page.
Let me know if I need to clarify anything and I can provide more code.
Rather than creating a new link element and appending it to the head, you could retrieve the contents of the stylesheet with an AJAX call, and insert it into an inline style block. That way, you can use jQuery's 'complete' callback to fire off your check.
$('#theme-selector a').click(function(){
var path = $(this).attr('href');
$.get(path, function(response){
//Check if the user theme element is in place - if not, create it.
if (!$('#userTheme').length) $('head').append('<style id="userTheme"></style>');
//populate the theme element with the new style (replace the old one if necessary)
$('#userTheme').text(response);
//Check whatever you want about the new style:
alert($('body').css('background-color'));
});
});
I haven't actually tested this code, so there may be some syntax-y errors, but the logic should be sound enough.
The load event can be watched for any element associated with a url, does this not work for you when loading the css stylesheet? http://api.jquery.com/load-event/
Try something like this:
var path = $(this).attr('href');
$('head link').remove();
var styleSheet = $('<link type="text/css" href="'+path+'" rel="stylesheet" />');
styleSheet.load(function(){alert("Loaded");});
$('head').append(styleSheet);
Edit: As pointed out below this only works in IE, who would have thought?
var cssLoaded = function()
{
alert($('body').css('background-color'));
};
$('#theme-selector a').click(function(){
var path = $(this).attr('href');
$('head link').remove();
$('head').append('<link onload="cssLoaded();" type="text/css" href="'+path+'" rel="stylesheet" />');
return false;
});
successfully tested in Chrome 28, IE 10, FF22
You could use lazyload (jQuery plugin) to load a css file.
It has the ability to call a function when the file is included.
Example:
// Load a CSS file and pass an argument to the callback function.
LazyLoad.css('foo.css', function (arg) {
// put your code here
});
Got here looking for a way to remove critical CSS ( element) after being 100% sure, that external sheets have lazyloaded and rendered. This would allow me to use universal, yet visually pleasing critical internal CSS globally over several projects.
Since some of the critical styles go visually against the lazyloaded ones, so they need to be overridden (too much work), or removed. This is what I want, in short:
Load the document with critical internal CSS
Lazyload the additional CSS after the document is rendered and interactive (good for SEO and UX)
Remove critical CSS from HTML after the fancy additional stylesheets have been loaded and truly rendered, to prevent flickering which occured with all other solutions (I have tested this a lot).
A 100% working solution (may it be unpopular) is to use setInterval(); after having the secondary css lazyloaded, to periodically check, whether a style, unique to secondary CSS has truly been applied. Then I can have the critical CSS removed (or whatever I want to do..).
I have created a live demo with comments on Codepen: https://codepen.io/Marko36/pen/YjzQzd and some info in a blogpost: Triggering a Javascript/jQuery event after CSS has loaded.
var CSSloadcheck = setInterval(function () {
if ($('body').css('opacity') != 1) {
//when opacity is set to 0.99 by external sheet
$('style#critical').remove();
clearInterval(CSSloadcheck);
}
}, 100);
You could simply keep on checking if the background colour is still the same, and then do your thing if ever it changes.
oldbackground=getbackground()
function checkbackground(){
if(oldbackground!=getbackground()){
oldbackground=getbackground()
//Do your thing
}
}
setInterval(checkbackground,100)

Categories

Resources