1

I am writing a diagnostic (greasemonkey) script for a very specific purpose, so I understand it may look odd. What I want to achieve is to display js and css info in a popup on a page so that it will show details that I can then use to troubleshoot/diagnose "our" products.

The following function is part of that script, and it builds a string (msg) which will be displayed in a popup window once all files have been diagnosed. This is working fine.

What I fail to understand is that towards the end of the code, I can "alert" the value (in this case, a line containing "Version"), yet I can't add that same value to the msg string that will be output later (and it will be displayed, including the closing ).

// get linked stylesheets
links = document.getElementsByTagName('link');
msg += '<h2>External Stylesheets</h2>';

for (var j in links) {
    if (links[j].rel == "stylesheet") {

        msg += "<div class='css" + [j] + "'>Stylesheet: " + "<a href=" + links[j].href + ">" + links[j].href + "</a>";
        var styleSheet = links[j].href;

        jQuery.get(links[j].href, function(data) {
            lines = data.split("\n");
            for (var k in lines) {
                if ((lines[k]).search(/Version/) != -1) {
                    alert (lines[k]);
                    msg += " - " + lines[k];
                    break;
                }
            }
        });
        msg += "</div>";
    }
}

I hope I made myself clear, I have a coding background, yet fairly new with the intricacies of Javascript/jQuery (that I added to the mix).

Edited: added a solution.

The asynchronous Ajax comments lead me to the solution (via the jQuery doc for jQuery.ajaxSetup), thanks everyone for your contribution, I learnt a lot.

First I tried:

jQuery.ajax({
    url: links[j].href,
    success: function(data) {
        lines = data.split("\n");
        for (var k in lines) {
            if ((lines[k]).search(/Version/) != -1) {
                msg += " - " + lines[k];
                break;
            }
        }
    },
    asynch: false
});

which for some reason did not work either, so I reverted back to my initial code (using jQuery.get) but added the following line at the beginning of the script:

jQuery.ajaxSetup({async:false});

and it's working as expected now with the code I already had.

ronald
  • 111
  • 5
  • What you mean "can't add"? Do you get error? Other stuff added instead of what you expect? Something else? – Shadow The GPT Wizard Jan 24 '12 at 13:10
  • 1
    Using the debugger for your favorite browser (f12 on chrome and IE, firebug extension on firefox...) set a breakpoint just before the error (or have the debugger pause on the first error automatically for you - its the stop sign on chrome, for example) and then check on the console (or on the local-variables tab) if all the values are what you expect they should be. Javascript debugging tools are very good so you should almost never have to resort to alerts :) – hugomg Jan 24 '12 at 13:17
  • as you already added jquery to your script, you might as well use other functions it provides. In your case, loops with `$.each` would make the code much clearer. And please declare your variables with `var` – Marcelo Diniz Jan 24 '12 at 13:22
  • Unfortunately I am not allowed to answer my own question, but I do want to share. Will have to wait a couple of hours, but in short: I added the following line at the beginning of the script: jQuery.ajaxSetup({async:false}); and it's working as expected now with the code above. [1]: http://api.jquery.com/jQuery.ajaxSetup/ – ronald Jan 24 '12 at 16:42
  • No! Don't use synchronous AJAX - it freezes the page. Write your code properly instead. – James M Jan 25 '12 at 00:26
  • Thanks James, I will continue to educate myself on writing proper code, as I agree that that **is** important, at the moment, my script works for me (it's for personal use). – ronald Jan 25 '12 at 12:36

3 Answers3

1
alert (lines[k]);
msg += " - " + this.lines[k];

lines[k] and this.lines[k] do not mean the same thing.

Also, you are aware that the jQuery.get is asynchronous and the callback will happen later, right? It looks like you're adding the </div> to msg before the callback will be invoked.

James M
  • 18,506
  • 3
  • 48
  • 56
  • I am sorry, I have removed "this" which was part of a test. Without "this" the result is the same, the version is not added to the "msg" string. – ronald Jan 24 '12 at 13:13
  • 1
    Updated my answer - I think it's your usage of the `jQuery.get` callback. – James M Jan 24 '12 at 13:16
  • Hi, I am not aware of that, and it may very well be causing this. What might be the proper way to "read" and retrieve the file contents? And thanks so much so far! – ronald Jan 24 '12 at 13:32
  • If you want to be sure you've already received the contents, your code has to be in (or called by) the `get` callback. You can't "wait" for it. – James M Jan 24 '12 at 13:37
0

Might not solve your problem, but better practice - use plain loops.

Change the loops to

for (var j = 0; j < links.length; j++) {

And:

for (var k = 0; k < lines.length; k++) {

The for each loop in JavaScript is meant for complex objects and when used on plain arrays it has some side effects that might cause weird behavior.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • thanks, I actually tried that as well, to no avail, but will keep that in mind – ronald Jan 24 '12 at 13:50
  • From reading further I think what you actually need is to perform [synchronous Ajax request](http://stackoverflow.com/questions/133310/) - this way the `msg` variable should hold the correct value in the end of the loop. – Shadow The GPT Wizard Jan 24 '12 at 14:12
0

Since the msg variable is result of async call.you should try this.

// get linked stylesheets
links = document.getElementsByTagName('link');
msg += '<h2>External Stylesheets</h2>';

for (var j in links) {
    if (links[j].rel == "stylesheet") {

        msg += "<div class='css" + [j] + "'>Stylesheet: " + "<a href=" + links[j].href + ">" + links[j].href + "</a>";
        var styleSheet = links[j].href;

        jQuery.get(links[j].href, function(data) {
            lines = data.split("\n");
            for (var k in lines) {
                if ((lines[k]).search(/Version/) != -1) {
                    alert (lines[k]);
                    msg += " - " + lines[k];

                    doYourPopupMessage(msg );
                    break;
                }
            }
        });


    }
}

function doYourPopupMessage(msg )
{
//do someting with msg
}
Ajeet Sinha
  • 2,315
  • 20
  • 20
  • this is part of a larger script, where I also loop through JS, and get other information, to finally get one string "msg" that I will show in a popup window. So I don't want to pop it up for each js or css file I find, but rather, once all files have been processed. Thanks though, I think we at least located the source of the issue (the jQuery.get) – ronald Jan 24 '12 at 14:05
  • You can try putting the msg in a global variable like use jQuery.data(document.body, 'foo', 52); but I am not sure will work because its a asynchronous call msg variable will be available after a time delay so it may happen that your entire files are processed and the variable is available after that. – Ajeet Sinha Jan 24 '12 at 14:15