When I use code like this, it works fine:
function removeWarning() {
var systemStatus = document.getElementById("system-status");
systemStatus.innerHTML = "";
}
function indicateInvalidUsername() {
var systemStatus = document.getElementById("system-status");
systemStatus.innerHTML = "Invalid username";
}
However, when I then want to move the systemStatus to be a global variable, it doesn't work:
var systemStatus = document.getElementById("system-status");
function removeWarning() {
systemStatus.innerHTML = "";
}
function indicateInvalidUsername() {
systemStatus.innerHTML = "Invalid username";
}
What am I supposed to be doing here?
It really depends on where your JavaScript code is located.
The problem is probably caused by the DOM not being loaded when the line
var systemStatus = document.getElementById("system-status");
is executed. You could try calling this in an onload event, or ideally use a DOM ready type event from a JavaScript framework.
Make sure you declare the variable on "root" level, outside any code blocks.
You could also remove the var altogether, although that is not recommended and will throw a "strict" warning.
According to the documentation at MDC, you can set global variables using window.variablename.
My guess is that the system-status element is declared after the variable declaration is run. Thus, at the time the variable is declared, it is actually being set to null?
You should declare it only, then assign its value from an onLoad handler instead, because then you will be sure that it has properly initialized (loaded) the element in question.
You could also try putting the script at the bottom of the page (or at least somewhere after the system-status element is declared) but it's not guaranteed to always work.
Declare systemStatus in an outer scope and assign it in an onload handler.
systemStatus = null;
function onloadHandler(evt) {
systemStatus = document.getElementById("....");
}
Or if you don't want the onload handler, put your script tag at the bottom of your HTML.
A global variable would be best expressed in an external JavaScript file:
var system_status;
Make sure that this has not been used anywhere else. Then to access the variable on your page, just reference it as such. Say, for example, you wanted to fill in the results on a textbox,
document.getElementById("textbox1").value = system_status;
To ensure that the object exists, use the document ready feature of jQuery.
Example:
$(function() {
$("#textbox1")[0].value = system_status;
});
To define a global variable which is based off a DOM element a few things must be checked. First, if the code is in the <head> section, then the DOM will not loaded on execution. In this case, an event handler must be placed in order to set the variable after the DOM has been loaded, like this:
var systemStatus;
window.onload = function(){ systemStatus = document.getElementById("system_status"); };
However, if this script is inline in the page as the DOM loads, then it can be done as long as the DOM element in question has loaded above where the script is located. This is because javascript executes synchronously. This would be valid:
<div id="system_status"></div>
<script type="text/javascript">
var systemStatus = document.getElementById("system_status");
</script>
As a result of the latter example, most pages which run scripts in the body save them until the very end of the document. This will allow the page to load, and then the javascript to execute which in most cases causes a visually faster rendering of the DOM.
Related
I have a functionality that I had running in the
window.addEventListener('load', function() {
var variable_name_1 = localStorage.getItem('var_1');
...
}
and I would like to move the functionality such that it only runs when the user clicks a button, in here:
function maketempuser() {
...
}
I can get the function to call when I want. But the function utilizes tons of variables from the load function. Is there a clean way to "globalize" these variables? Or must I find some way to add all these variables in the html:
<button ... onclick='maketempuser(variable_name_1, variable_name_2, ...);' >
NOTE: the javascript will run the same file, I just don't want it to keep re-running every time the user reloads the page since there is an ajax mysql insert that occurs because this page is one in a line of pages that enables a user to register.
To not pollute the global scope with a lot of variables (which can be overridden by other apps), I recommend you create an object with an app specific name, maybe something like this
var myAppVar = {};
window.addEventListener('load', function() {
myAppVar.var_1 = localStorage.getItem('var_1');
...
}
Just define them in global scope:
var variable_name_1;
window.addEventListener('load', function() {
variable_name_1 = localStorage.getItem('var_1');
...
}
This, however, is not a particularly healthy technique, since it's prone to name collisions. Best thing to do is have a custom object (cO, or with your initials, something unlikely to be used by anything else) and use it as a placeholder for all your custom vars:
var cS = {
var_1:null // or some default value...
};
window.addEventListener('load', function() {
cS.var_1 = localStorage.getItem('var_1');
...
}
Since localStorage is already global just retrieve the values you need in your handler from there.
function maketempuser() {
var variable_name_1 = localStorage.getItem('var_1');
}
No need to add anything extra to the global scope at all.
This question asks for a way to open a new window using window.open and then inject it with a script. It was not possible because of cross-domain security issues.
However, my problem is that I want to do the exact same thing, except from the same domain to the same domain. Is this possible?
Note that .write does not solve this problem because it wipes all the html from the page first.
You can do something like this:
var theWindow = window.open('http://stackoverflow.com'),
theDoc = theWindow.document,
theScript = document.createElement('script');
function injectThis() {
// The code you want to inject goes here
alert(document.body.innerHTML);
}
theScript.innerHTML = 'window.onload = ' + injectThis.toString() + ';';
theDoc.body.appendChild(theScript);
This also seems to work:
var theWindow = window.open('http://stackoverflow.com'),
theScript = document.createElement('script');
function injectThis() {
// The code you want to inject goes here
alert(document.body.innerHTML);
}
// Self executing function
theScript.innerHTML = '(' + injectThis.toString() + '());';
theWindow.onload = function () {
// Append the script to the new window's body.
// Only seems to work with `this`
this.document.body.appendChild(theScript);
};
And if for some reason you want to use eval:
var theWindow = window.open('http://stackoverflow.com'),
theScript;
function injectThis() {
// The code you want to inject goes here
alert(document.body.innerHTML);
}
// Self executing function
theScript = '(' + injectThis.toString() + '());';
theWindow.onload = function () {
this.eval(theScript);
};
What this does (Explanation for the first bit of code. All examples are quite similar):
Opens the new window
Gets a reference to the new window's document
Creates a script element
Places all the code you want to 'inject' into a function
Changes the script's innerHTML to load said function when the window
loads, with the window.onload event (you can also use addEventListener). I used toString() for convenience, so you don't have to concatenate a bunch of strings. toString basically returns the whole injectThis function as a string.
Appends the script to the new window's document.body, it won't actually append it to the document that is loaded, it appends it before it loads (to an empty body), and that's why you have to use window.onload, so that your script can manipulate the new document.
It's probably a good idea to use window.addEventListener('load', injectThis.toString()); instead of window.onload, in case you already have a script within your new page that uses the window.onload event (it'd overwrite the injection script).
Note that you can do anything inside of the injectThis function: append DIVs, do DOM queries, add even more scripts, etc...
Also note that you can manipulate the new window's DOM inside of the theWindow.onload event, using this.
Yes...
var w = window.open(<your local url>);
w.document.write('<html><head>...</head><body>...</body></html>');
Here's a trick I use, it uses query strings, and is client side. Not perfect but it works:
On the sending page, do:
var javascriptToSend = encodeURIComponent("alert('Hi!');");
window.open('mypage.html?javascript=' + javascriptToSend);
Replace mypage.html with your page. Now on the receiving page, add:
(location.href.match(/(?:javascript)=([^&]+)/)[1])&&eval(decodeURIComponent(location.href.match(/(?:javascript)=([^&]+)/)[1]));
You'll have to do some back-and forth to make sure this works.
If you HAVE PHP you can use this more reliable solution on the receiving page:
eval(decodeURIComponent(<?=$_GET['javascript'] ?>));
I'm not using eval, and I'm not sure what the problem is that Crockford has with the following. Is there a better approach to solve the following problem or is this just something I need to ignore (I prefer to perfect/improve my solutions if there is areas for improvement).
I'm using some pixel tracking stuff and in this case a client has bound a JS function to the onclick property of an HTML image tag which redirects off the site. I need to track the clicks reliably without running into race conditions with multiples of event listeners on the image. The strategy is to override the event at run time, copying and running it in my own function. Note this is being applied to a site I do not control and cannot change. So the solution looks something like:
...
func = Function(img.attr('onclick'));
...
img.attr('onclick', '');
... //some custom tracking code
func.call(this);
and the JSLint checker throws the eval is evil error.
Is there a better way to avoid race conditions for multiple events around href actions?
You're implicitly using eval because you're asking for the callback function as it was specified as an attribute in the HTML as a string and then constructing a Function with it.
Just use the img.onclick property instead, and you will directly obtain the function that the browser built from the attribute that you can then .call:
var func = img.onclick; // access already compiled function
img.onclick = null; // property change updates the attribute too
... // some custom tracking code
func.call(img, ev); // call the original function
or better yet:
(function(el) {
var old = el.onclick;
el.onclick = function() {
// do my stuff
..
// invoke the old handler with the same parameters
old.apply(this, arguments);
}
})(img);
The advantage of this latter method are two fold:
it creates no new global variables - everything is hidden inside the anonymous closure
It ensures that the original handler is called with the exact same parameters as are supplied to your replacement function
var oldClick = myImg.onclick;
myImg.onclick = function(evt){
// Put you own code here
return oldClick.call( this, evt );
};
I have a pretty specific question. I am trying to implement an onclick and cross domain tracking within a block of text, but it looks like it may need to be put directly into a .js document. I don't have a lot of JS experience. Basically, the current code looks like:
// JavaScript Document
function popup_no_status(loc)
{
var windowW=1000
var windowH=700
s = "width="+windowW+",height="+windowH+",status=yes, resizable=yes, scrollbars=yes";
mywin = window.open(loc ,'CBE', s);
mywin.focus();
}
What I want to add to this is:
onclick="pageTracker._trackEvent('Button', 'Click', 'QuickSearchWidget'); pageTracker._link(this.href); return false;
Can I just add it to the end of the document before the closing bracket? Any Ideas?
Much appreciated!
As long as the object pageTracker is defined and instantiated, you can call its methods like any other function:
function popup_no_status(loc) {
var s = "width=700,height=1000,status=yes, resizable=yes, scrollbars=yes";
var mywin = window.open(loc ,'CBE', s);
mywin.focus();
pageTracker._trackEvent('Button', 'Click', 'QuickSearchWidget');
pageTracker._link(this.href);
}
Also, the variables windowW and windowH are pointless in your example code - there is no need to store the string values in a variable if all you're going to do is concatenate them into another string. Further, unless you intend the mywin and s variables to be global, you should use the var keyword before defining them - that restricts the variables to the function scope instead of the global scope (all variables declared in a function without the var keyword are considered global).
If the code above gives an error like ReferenceError: pageTracker is not defined, that means that the code in which the pageTracker object is defined is either not included on the page, or it has not been instantiated.
Now... as for onClick, I am not clear what you're after here. Do you want this function to run when someone clicks the document? That would get pretty annoying!
I am writing a simple counter, and I would like to make installation of this counter very simple for users. One of the simplest counter code (for users who install it) I ever see was Google Analytics Code
So I would like to store main code in a file and user who will install my counter will need just to set websiteID like this:
<html><head><title></title></head><body>
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var websiteId = 'XXXXX';
</script>
</body></html>
Here is my code:
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var page = _gat.init('new');
</script>
and this is my JS file:
(function() {
var z = '_gat';
var aa = function init(data) { alert(data); alert(z);};
function na() {
return new z.aa();
}
na();
})();
I tried to understand Google Analytics javascript code but I failed to do this. Can anyone suggest how can I specify variable between tags and then read it in anonymous function which is located in a javascript file ?
Thanks.
In your example, websiteId is a global variable. So it is accessible everywhere including anonymous functions unless there is a local variable with the same name
<script> var websiteId = "something"; </script>
Later in the page or included js file...
(function() {
alert(websiteId); //this should work
})();
Can anyone suggest how can I specify variable between tags and then read it [...]
Not if your tag has both a SRC attribute and JS content.
<script type="text/javascript" src="http:/x.com/x.js"></script>
.. is different from,
<script type="text/javascript">
var x = 1;
</script>
One framework that optionally adds JS variables to SCRIPT tags is Dojo. So if you're using Dojo you can add variables to the global djConfig hash by writing,
<script type="text/javascript" src="mxclientsystem/dojo/dojo.js"
djConfig="
usePlainJson: true,
parseOnLoad: true
">
</script>
Dojo does this by running through the SCRIPT tags and evaluating the custom djConfig attribute.
This does not, however solve your problem.
You do really want two SCRIPT tags. One saying,
<script type="text/javascript">
var websiteId = '123456';
</script>
which will set a global variable websiteId and a second one,
<script type="text/javascript" src="http:/x.com/myreporter.js"></script>
which can load from anywhere and read out the websiteId variable and, I assume, report it back.
You can pass variables to an anonymous function like so:
(function(arg1, arg2, arg3) {
alert(arg1);
alert(arg2);
alert(arg3);
})("let's", "go", "redsox");
// will alert "let's", then "go", then "redsox" :)
I'm not entirely clear about what you're asking, but...
You can tag any HTML element with an id attribute, then use
document.getEntityById() to retrieve that specific element.
You can also give any HTML element user-defined attributes having names of your own choosing, then get and set them for that element within Javascript.
I think you've got a bit confused with how JS objects are called.
z is a String, '_gat'. You can't call aa() on it because a String has no member called aa. aa is a standalone function stored in a local variable. Even if you did call aa(), it doesn't return anything, so using the new operator on its results is meaningless. new can only be called on constructor-functions.
I guess you mean something like:
var _gat= function() {
// Private variable
//
var data= null;
// Object to put in window._gat
//
return {
// Set the private variable
//
init: function(d) {
data= d;
}
};
}();
Then calling _gat.init('foo') as in your second example would set the variable to website ID 'foo'. This works because the _gat object is the return {init: function() {...}} object defined inside the anonymous function, keeping a reference (a ‘closure’) on the hidden data variable.
If you specify a src attribute as part of a script element, any code within the script element tags themselves will not be executed. However, you can add this functionality with the following code. I got this technique from Crockford (I believe it was him), where he uses it in of his talks on the unrelated topic of rendering performance and asynchronously loading scripts into a page to that end.
JavaScript:
(function() {
// Using inner class example from bobince's answer
var _gat = (function() {
var data= null;
return {
init: function(d) {
console.info("Configuration data: ", d);
data = d;
}
}
})();
// Method 1: Extract configuration by ID (SEE FOOT NOTE)
var config = document.getElementById("my-counter-apps-unique-and-long-to-avoid-collision-id").innerHTML;
// Method 2: search all script tags for the script with the expected name
var scripts = document.getElementsByTagName("script");
for ( var i=0, l=scripts.length; i<l; ++i ) {
if ( scripts[i].src = "some-script.js" ) {
config = scripts[i].innerHTML;
break;
}
}
_gat.init( eval("(" +config+ ")") );
})();
HTML:
<script type="text/javascript" src="some-script.js" id="my-counter-apps-unique-and-long-to-avoid-collision-id">
{some: "foo", config: "bar", settings: 123}
</script>
Both methods have their draw backs:
Using a unique and non-colliding ID will make determining the proper script element more precise and faster; however, this is not valid HTML4/XHTML markup. In HTML5, you can define arbitrary attributes, so it wont be an issue at that time
This method is valid HTML markup; however, the simple comparison that I have shown can be easily broken if your url is subject to change (e.g.: http vs https) and a more robust comparison method may be in order
A note on eval
Both methods make use of eval. The typical mantra concerning this feature is that "eval is evil." However, that goes with say that using eval without knowing the dangers of eval is evil.
In this case, AFAIK, the data contained within the script tags is not subject to inject attack since the eval'ing script (the code shown) is executed as soon as that element is reached when parsing the HTML into the DOM. Scripts that may have been defined previously are unable to access the data contained within the counter's script tags as that node does not exist in the DOM tree at the point when they are executed.
It may be the case that a well timed setTimeout executed from a previously included script may be able to run at the time between the counter's script's inclusion and the time of the eval; however, this may or may not be the case, and if possible, may not be so consistently depending on CPU load, etc.
Moral of the story, if you're worried about it, include a non-eval'ing JSON parser and use that instead.