How can I clear references to Javascript functions that no longer exist? - javascript

I am working on a project that uses AJAX to download HTML, CSS and Javascript in one singe chunk of text then appends it to an element on the page. Here is the code:
_t.stage.empty();
_t.stage.html(DATA);
This works fine.
Here is the problem:
After adding the HTML to the stage, I call this function:
if(initApp != null && typeof(initApp) == "function") initApp();// Checks for initApp(). If exists, executes.
If I load a page that has this function, then load one that does NOT have this function, the function from the first page is executed. Here is some psuedo code to understand the results.
page 1:
This is a page.
<style>...</style>
<script> function initApp(){ alert("hello"); } </script>
When this page is run, an alert box with the text 'hello' is shown.
page 2: (no initApp() function)
This is page 2.
<style>...</style>
When the page is run, an alert box with the text 'hello' is shown.
Please note: These pages are loaded with AJAX and inserted into the HTML of an already loaded page.

It is not easy to tell exactly what you're trying to do, but if what you're trying to do is make it so that some other code that calls initApp() will cause nothing to happen when it calls that, then you can simply redefine the function to a do-nothing function like this:
initApp = function() {}
The most recent definition of a function takes precedence (e.g. replaces any prior definitions).
If your newly loaded code contains an implementation of initApp() that you don't want called the second time the script is loaded, then you're out of luck. You can't stop that. You will need to change the structure of your code so that the dynamically loaded code doesn't execute stuff you don't want to be executed. There are many different ways you could do that. For example, you could have a global boolean that keeps track of whether the init code has been called yet.
var initCalled = false;
function initApp() {
if (!initCalled) {
initCalled = true;
// rest of initialization code here
}
}
initApp(); // will only actually do anything the first time it's called
// even if it is loaded more than once
It appears from the comments that you seem to think that reloading a script tag with different code will somehow make code from the previous script go away. It will not. Once a function is loaded, it stays loaded unless it is redefined to mean something else or unless some code explicitly removed a property from an object. It does not matter how the code was loaded or whether it was in the core page or an external script file.

Javascript functions that no longer exist
This is a bad premise. The functions still exist, which is obvious from the fact that the second AJAX load ended up executing it. The fact that the <script> tags are replaced and no longer in the document doesn't undefine the function. It's like asking why is your TV still broken if the burglar that broke it is no longer there.
There are two basic things you can do:
a) Clear the function explicitly yourself:
if (initApp != null && typeof(initApp) == "function") {
initApp();
delete window.initApp;
}
b) Change the function name to be unique per AJAX page (or namespace the function with the same idea), probably tied to the name of the AJAX page, so you can invoke it in a more specific manner.

Related

Swift - execute Javascript on each page

I have a UIWebView to which I pass a HTML file to load.
The HTML file includes javascript that looks for the existence of a variable.
If it exists, it performs one action, if the variable doesn't exist, the script performs another action.
if(typeof customVar === 'undefined')
//Perform task1
else
// Perform task 2 using customVar
On the native, I use the function stringByEvaluatingJavaScriptFromString to set the variable before the page is loaded.
To do so, I'm setting the code in webViewDidStartLoad (I also tried to place it in shouldStartLoadWithRequest).
func webViewDidStartLoad(webView: UIWebView)
{
let cutVar = "test"
webView.stringByEvaluatingJavaScriptFromString("customVar = '\(cutVar)';")
}
This works well when I load a page for the first time, but only the first time.
After that, it seems that through the webViewDidStartLoad, we re-assign the variable in the current page, and then reload the page itself.
So that means, the page is reloaded without the variable to be set.
Is there a way to say I want to run the javascript bit for the next page to load?
Maybe something like a global variable always accessible?
Thank you.

JavaScript top or bottom - location sensitive?

Why does a linked JavaScript file sometimes not work when it is included at the top of the page and not at the bottom?
<script type="text/javascript" src"..."></script>
For example, if you want to manipulate DOM items, and those are not yet existing, it won't work. If the JavaScript file is included in the head, the body is not existing yet, but if you include it at the end of the body, those items are valid.
If you don't want to rely on this behaviour, you may define a callback, which is run, when the document is ready, i.e. when the whole of the DOM is loaded already.
This is what e.g. jQuery achieves with $(document).ready(function() {}), or more shortly $(function () {});. In vanilla JavaScript (using modern browsers, so IE9+) this can be achieved using
document.addEventListener("DOMContentLoaded", function() {
// code...
});
The best way to know why is it not working is by checking for JS error. Try to find out what errors you are getting when the script has been included at the top. As mentioned in the other response it can be because of DOM items. You can circumvent this issue by adding a "defer" tag to the script.
It can also be because of some JS object you are expecting to be present when this script runs. For example if your script tag is serving a JSONP request then you must have the function that processes the data. Otherwise you will get a "undefined function" error when the script runs.
JS code is executed instruction by instruction from top to bottom.
The code that calls a function needs to be under that functions definition.
This code works:
var func = function()
{
alert('it works');
};
func();
While this doesn't:
func();
var func = function()
{
alert('it works');
};
It throws an undefined error. The reason for this is that JS compiler is not aware of the func definition at the time it tries to call it.
Same goes for the JS files included in your HTML page. You can include them at the bottom as long as there are not dependencies in above sections, or, if they do not try to manipulate HTML code before page load.

Basic JQuery syntax: What mechnaic is at work in this small (2 line) piece of JavaScript / JQuery

So here' s the piece of code. I'm very new to JavaScript so don't be afraid to explain the obvious
$(".my-css-class").on("click", function() {
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
});
There's an element in the .jsp page that looks like this:
<i class="clickMe"></i>
I know the .jsp creates a link-icon, and that the above JavaScript is an event handler. I know that it passes these 3 values as arguments another JavaScript method:
function doStuff(prop1, prop2, obj) {
if (prop1 == 'foo') {
//do stuff with prop2
}
else{
// do stuff with obj
}
}
It all works fine. What I want to know is what exactly is going on to make it work? I can't find anything in the code that connects what the event-handler returns to the 'doStuff' java-script function.
The names are totally different, so it's not reflection, it can't be parameter matching because there's other functions with the same number and type of parameters in the file, it can't be convention based because it still works if I find/replace the name of the function to gibberish.
I guess basically I'm asking what this line is doing:
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
tl;dr: I'm at a loss, I know how the properties get as far as the onClick event-handler's anonymous function - but how does JavaScript know to pass them as arguments the to the doStuff() function?
the onClick event is a standard event triggered on click of any clickable html element and is automatically raised by the DOM.
You are hooking in to this by listening on any matched ".my-css-class" elements for an onClick Event.
The jquery syntax ".on" has been simplified over time and allows you to hook into any number of events like "submit" - OnSubmit event , or "load" - onLoad Event
Wherever your on("click", myFunction) event hook is picked up, your myFunction will execute.
Looking at your second point...
because it still works if I find/replace the name of the function to gibberish.
The DoStuff function will be found and replaced across all files in your site? or page? or open tabs? , so therefore it must exist somewhere as "doStuff(" or "giberish(".
so when you do a global find/replace, do each one slowly, until you locate it.
Finally, when you do a view source in the browser, this should either explicitly show you the doStuff function, or at the very least give you a clue as to satelite files loaded at runtime, where you can go and investigate.
Use firebug in firefox to debug loaded resources; the ".net tab" to view external loaded resources and the html/javascript they might contain. (for example: your master page might be loading in an embeded resource that contains the doStuff method, becuase of a user or server control reference in that master page)
Also have a look at this:
http://www.developerfusion.com/article/139949/debugging-javascript-with-firebug/
You can step through the javascipt piece by peice until it hits the doStuff method.
Just remember to set at least 1 breakpoint ;-)

Javascript: Performing action once the next page has loaded?

I am currently building a google extension and this is what I'm going for:
Do something on awesome.page1.html then automatically press Next Page. When the new page has loaded, fill in a form's textfield.
My issue is that even though I know how to fill in the textfield, I don't quite know how to tell it to fill it in once page2 has loaded. It keeps trying to do everything on page 1.
This is what I'm trying but it's not working:
function addEffect() {
document.getElementsByClassName("effect1 shine")[0].click();
document.getElementsByClassName("nextPage BigButton")[0].click();
nextStep();
}
function nextStep() {
if(document.getElementsByClassName("myformTextField imageName") != undefined) {
alert('Page 2 is up.');
}
else {
alert('Page 1 is still up.');
setTimeout("nextStep()", 250);
}
}
I'm using an alert just for testing, and I keep getting the "Page 2 is up" even though it is still on page 1. I'm checking if an element, which is only present in page 2, is up. How could I make sure page2 is up?
The major issue you're going to run into is that JavaScript variables--including functions--don't persist from one page to another. Put another way, you can't write a function on one page and have it execute on the page that replaces it.
You could pass a URL variable or set a cookie for data persistence--or store settings on your server--but a straight JavaScript approach won't work.
Of course, there is a little trick that some folks use to load the entire DOM of the next page into a variable (using a variation on an XMLHttpRequest), apply the stored settings to the object in memory, and then replace most of the document body with most of the new DOM, but that's probably far more complicated than you need, and it has to conform to same-domain requirements.
Well, your code here:
document.getElementsByClassName("myformTextField imageName")
returns an empty array when it finds nothing, which is not undefined. Therefor, your first if condition will always be true, regardless if it finds your item or not.
Instead, check the length returned by getElementsByClassName or use querySelector and check for null
if (document.getElementsByClassName("myformTextField imageName").length) { ... }
// Or..
if (document.querySelector('.myformTextField.imageName') !== null) { ... }
The easiest method I chose to go with was content script matches.
What I did was create two separate javascript files in my extension: 1.js and 2.js. When awesome.page1.html loads it will run 1.js and when page2.html loads it will run 2.js.
All I did in my manifest.json file is the following:
"content_scripts":[
{"matches": ["http://awesome.page1.com/*"], "js": ["1.js"]},
{"matches": ["http://page2.com/*"], "js": ["2.js"]}]
you should try to user jquery and the $(document).ready(handler)
this is really a best practice to ensure that the page is loaded before it tries to execute your commands
http://api.jquery.com/ready/

What is the proper way to fire two scripts: one that loads data and another that manipulates styling?

I'm running a website that dynamically loads a new headline at refresh using JavaScript. I should mention, my site is extremely tiny so I'm purposefully avoiding using jQuery or any other JS libraries.
First script loads a JSON file and randomly selects an entry into the HTML. Second script "attempts" to check if the document's length runs past the viewport, if it does, shrink the text and check again.
ajax.request("GET","file.json"); // works fine
preventScroll.resize(".headline"); // not so much
However, I can't get the second script to work reliably. I've tried loading both through window.onload, I've tried moving it from the HEAD tag to immediately before the end of the BODY tag.
Scripts in question
Live Example
How should I properly call these so they always work?
You're not exposing a success handler in your ajax "library". I would suggest making these changes:
var makeRequest = function(method, url, success) {
Then inside the function:
//...
if (httpRequest.status === ajaxState.isOkay) {
data = httpRequest.responseText;
successHandler(data);
success(); // you could call with more arguments
}
To use the whole thing together:
ajax.request("GET","file.json", function() {
preventScroll.resize(".headline");
});

Categories