1

SOLVED. I changed my code into this:

function init() {
    //preloadImages();
    getContent('events', 'events');
    getContent('content', 'main');
}

function loadingScreen(start) {
    var loadingSpan = document.getElementById('loading');
    if (start == true) {
            loadingSpan.innerHTML = '<p>Loading...<br><img src="images/loading.gif"></p>';
    }
    else {
            loadingSpan.innerHTML = '';
    }
}

function getContent(what, where) {
    if (what == 'content') {
            loadingScreen(true);
            var ranLoad = true;
    }
    var toSet = document.getElementById(what);
    var location = "content/" + where + ".txt";
    var request = new XMLHttpRequest;
    request.open("GET", location, true);
    request.onreadystatechange = function(){
            if (request.readyState == 4 && request.status == 200){
                    toSet.innerHTML = request.responseText;
                    if (ranLoad==true){
                            loadingScreen(false);
                    }
            }
    }
    request.send(null);
}
window.onload = init;

tl;dr or long-winded - see the code and the results below.

So. I am building a small webpage for a friend, and I decided to try out a technique where instead of writing the content directly in the webpage, I will use XMLHttpRequest to retrieve content (in the same domain), and place them in the content , where it will be updated by javascript, when people click on a different anchor. Well, I came across a roadbump. When I created the functions for getting the content (setEvents and setContent), where it creates a variable and calls a function for setting the variable (getMarkup), when the function was called, and the return statement was executed, it returns undefined. I found a thread similar, but their solution was to add the innerHTML statement DIRECTLY in the getMarkup function. I don't want to do that.

Here's the code and the results:

Edit: Esailija suggested that I should have just posted the code. To me it was a tad bit easier to just take the image, but here it is:

function init() {
    //preloadImages();
    setEvents();
    setContent('main');
}

function setEvents() {
    var eventDiv = document.getElementById("events");
    var eventContent = getMarkup("content/events.txt");
    eventDiv.innerHTML = eventContent;
}

function setContent(which) {
    loadingScreen('start');
    var contentDiv = document.getElementById('content');
    location_ = "content/" + which + 'txt';
    //var contentContent = getMarkup('location');
    //contentDiv.innerHTML = contentContent;
    loadingScreen('stop');
}

function loadingScreen(action) {
    var loadingSpan = document.getElementById('loading');
    loadingSpan.innerHTML = "Test";
    if (action == 'start') {
        loadingSpan.innerHTML = '<p>Loading...<br><img src="images/loading.gif"></p>';
    }
    if (action == 'stop') {
        loadingSpan.innerHTML = '';
    }
}

function getMarkup(where) {
    var filerequest = new XMLHttpRequest();
    filerequest.open("GET", where, true);
    filerequest.onreadystatechange = function() {
        if (filerequest.readyState == 4 && filerequest.status == 200) {
            var test = document.getElementById("events");
            var reply = filerequest.responseText;
            //Doesn't work
            return reply;
            //Works just fine
            //test.innerHTML = reply;
        }
    };
    filerequest.send(null);
}
window.onload = init;

When I do the innerHTML instead of return it shows "Test TEST", and when I do return instead of innerHTML, it shown "undefined".

I really don't want to do the innerHTML part of it, so is there a workaround to make that return statement work?

Ivan Kay
  • 15
  • 1
  • 2
  • 6

2 Answers2

0

Are you familiar with callbacks? Open up Firebug and put a breakpoint on your return reply; line - notice the call stack. The function where you have return reply; is not getMarkup.

Basically you're going to have to restructure your code a little. I would have getMarkup take an additional parameter - the DOM element to which you want to set its innerHTML value.

Andy Gaskell
  • 31,495
  • 6
  • 74
  • 83
  • AUGH, that's right. Basically, what you are telling me, is that because it is in it's own function, it will not return like I want it to, right? I am going to test it right now. – Ivan Kay Jul 15 '12 at 16:34
  • @IvanKay yes, it will `return reply` to whatever that is calling the `onreadystatechange`, probably something internal in the browser. The `return statement` only affects the function where it's placed. – Esailija Jul 15 '12 at 17:07
  • @Esailija Okay, thanks. I just now redid the code into one function and now it works. – Ivan Kay Jul 15 '12 at 20:34
0

It seems that you don't quite understand how ajax works.
Once you call your getMarkup function, you send an ajax request and tell the browser to use the function after onreadystatechange to handle the reply. So actually when the reply is back, it's not your other functions like setContent that are calling that handler but the browser. That's why the return doesn't work.

Also when you call something like var contentContent = getMarkup('location'); , as getMarkup has no explicit return value, so by default contentContent gets undefined. You may think that it should get the return value inside your anonymous function but that's not the case. The getMarkup function returns immediately but the handler will be called only when the ajax response comes.

If you want to make that nice, you will have to do something extra like: you only have one ajax handler like you did. Once a function called that ajax function it register its callback into a queue and when the response is back the queue is popped and the values are then updated. This would take some time for you to build this mechanism or you may need to check how the jQuery Ajax Queue works.

NSF
  • 2,499
  • 6
  • 31
  • 55
  • Yes, Andy Gaskell explained it quite nicely for me. And I'm quite new to Javascript, so I want to get a good grip on how everything works, and then I will start learning jQuery. I just like learning things one thing at a time. C: – Ivan Kay Jul 15 '12 at 20:39
  • Yea jQuery hides a lot of stuff behind it and thus it's not good start to learn things by using it. Your approach is good although it may take more time for you than those who starts learning frontend using jQuery – NSF Jul 15 '12 at 21:50
  • Yes, but to me, that's the way I learn best. Juggling a hundred things at a time is not very pleasant, you know. ;) – Ivan Kay Jul 15 '12 at 23:57