tags:

views:

190

answers:

3

I am trying to load the statcounter script from my custom js file. The original script looks like this:

<html>
<head>...</head>
<body>
...
<script type="text/javascript">
var sc_project=11111111;
var sc_invisible=1;
var sc_partition=11111111;
var sc_click_stat=1;
var sc_security="11111111";
</script><script type="text/javascript" src="http://www.statcounter.com/counter/counter_xhtml.js"&gt;&lt;/script&gt;
...
</body></html>

The code seems to set the variables, then loads the counter script which reads the values of the variables and does its job. I'm trying to call the counter script like this:

// file: counters.js
function CounterFromStatCounter() {
  sc_project=11111111;
  sc_invisible=1;
  sc_partition=11111111;
  sc_click_stat=1;
  sc_security="11111111";

  var oHead = document.getElementsByTagName('HEAD').item(0);
  var oScript= document.createElement("script");
  oScript.type = "text/javascript";
  oScript.src="http://www.statcounter.com/counter/counter_xhtml.js";
  oHead.appendChild( oScript);
}

 // main page
<html>
<head>
...
<script type="text/javascript" src="counters.js"></script>
...
</head>
<body>
...
<script type="text/javascript">
  CounterFromStatCounter();
</script>
...
</body></html>

The code seems to work: the script element that references the statcounter script appears in the head section as it should, but no visits are recorded - this means that the variables set in my script cannot be accesed by the counter script.

What am I doing wrong?

+2  A: 

You are doing a couple of things wrong.

1) You likely have not validated your code. Go to http://jslint.com and validate your JavaScript.

2) Do not write JavaScript into your HTML. That has a tendency to force all code bits into the global namespace, which is very likely to produce collisions with any other JavaScript code.

3) Only reference external JavaScript files directly prior to the closing body tag. Script interpretation blocks parallel downloads in IE.

Accomplish those three and then come back for more help.

3) on the to do list
alexandrul
2) what other options do I have considering that the statcounter script runs when loaded and needs to acces the sc_* variables?
alexandrul
1) JSLint gives only one error: "Implied global: sc_project 2, sc_invisible 3, sc_partition 4, sc_click_stat 5, sc_security 6, document 8,9" when no option is selected. With "The Good Parts" options selected, it just hurts all my little feelings.
alexandrul
JSLint validation passes if using "/*global document, sc_project: true, sc_invisible: true, sc_partition: true, sc_click_stat: true, sc_security: true */". The only problem seems to be how to set the sc_* variables in my script in order to be accesed from the statcounter script which is later loaded by my script.
alexandrul
#2 is nonsense. Inline scripts and scripts included over HTTP have exactly no difference in terms of how they relate to the global scope. And both allow the use of closures to avoid polluting the global scope.
eyelidlessness
@eyelidlessnes - You are wrong. Code declared inline to the HTML without being wrapped in a function is executed as it is interpreted, which does contaminate the global namespace exactly as implied globals variables of external script files. That problem is solved by always using functions as containers, always declaring variables inside functions using the var command, and always placing that code in external script files.
@alexandrul - The proper way to ensure all the necessary code get executed upon loading of the page is to put all the function names that you need loaded into another function. The use the onload event in the body tag and reference this new function. Everything inside the new function will get executed the moment the page has completely loading.
+1  A: 

Define the variables globaly and write some js like below.

window.attachEvent('onload', function() {
   document.write('<script type=text\/javascript src=blabla.com\/counter.js><\/sc' + 'ript>');
});

this should work in IE. For other other browsers implement addEventListener...

Emrah GOZCU
The loading of the statcounter script is working, I can't make the sc_* variables available to the statcounter script.
alexandrul
Defining the variables globally is an extremely bad practice.
How extremely it is, can it explode? Come on it is no more than five variable and do you think it can be reachable from a script file if the variables not defined globally for all browser in the market.
Emrah GOZCU
When you working with an application in JavaScript that has hundreds of variables it only takes a single poorly written script supplied with an ad to cause a collision makes all JavaScript on the page fail. So, yes, it can cause the JavaScript to explode. That one function is no more than 5 variables and it is extremely ignorant to presume the entire site will be limited to serving only that one function.It is better to do it correctly the first time and not be sloppy to allow errors to creep in.
Is there any genius out there to tell me how you are going to pass the variables to a function in a referenced external js if you are not using server side programming besides that if you have no reach to change the file. Instead, putting something like var someVariable = 'ITISAVARIABLE'; Like google does in google analytics code?Genius?
Emrah GOZCU
+1  A: 
var CounterFromStatCounter = function () {
    var sc_project = 11111111,
    sc_invisible = 1,
    sc_partition = 11111111,
    sc_click_stat = 1,
    sc_security = "11111111",
    oHead = document.getElementsByTagName('head').item(0),
    oScript= document.createElement("script");
    oScript.setAttribute("type", "text/javascript");
    oScript.setAttribute("src", "http://www.statcounter.com/counter/counter_xhtml.js");
    oHead.appendChild(oScript);
}

I have looked at the above code more closely and here are my thoughts:

1) That is how the code should look once beautified and reduced to a single var command in your function without any implied globals, except for the function name itself.

2) Dynamically created content from client-side code is destroyed each time the page loads at each user. So you will likely not want to write output using JavaScript as any means of providing a data reference point. I recommend doing this completely on the server side to be more efficient. If you must use JavaScript you will need to write to some intermediate data store, like a JSON, file that you connect to using the xmlHttpRequest object.

3) I would not recommend writing anything to the head of the document dynamically from the client-side due to different interpretations of the DOM between browsers and also once the head is loaded the browser has no reason to read it again for new information.

4) To be most efficient scripts should be in external files that referenced just before the closing body tag, because script interpretation blocks parallel downloads in IE. Putting scripts in the head is results in dramatically slower page loads in IE as a result.

5) I changed "HEAD" to "head" because JavaScript and XHTML are both case sensitive.

6) I also changed the way attributes are appended to your dynamically created script tag to use DOM methods. I don't know if this is the more correct method, but it is certainly more inline to the standards.

Thank you for your help, but I am trying to move the call to the statcounter script to a separate file. Since statcounter script is not under my control, I must make the variables as global in my file in order to be available to the other script - which is still not working, but it could be a problem with the statcounter site. +1 for the rest of your answer.
alexandrul