Patrick Reck
Patrick Reck

Reputation: 11374

AJAX doesn't automatically update before button is pressed

I'm making a conversation system where 2 people can chat with each other. I've made an AJAX function which updates the DIV box containing the messages every 2 seconds.

This is working as intended, after a user have written a message. Why isn't the AJAX call being run right away?

// SET AUTORUN updateMessages() EVERY 2 SECONDS
$(document).ready(function() {
    var interval
    window.onload = function(){
        interval = setInterval('updateMessages()', 2000);
    };
});

// UPDATE #mail_container_conversation
function updateMessages() {
    $.ajax({
        type: "POST",
        url: "<?php echo site_url(); ?>mail/ajaxupdate/<?php echo $user; ?>",
        data: dataString,
         
        success: function(data){
            $("#mail_container_conversation").html(data);
        }        
    });
}


// SEND NEW MESSAGE
$(function(){
    $("#mail_send").submit(function(){
        dataString = $("#mail_send").serialize();
         
        $.ajax({
        type: "POST",
        url: "<?php echo site_url(); ?>mail/send",
        data: dataString,
         
        success: function(data){
            updateMessages();
            $(".mail_conversation_answer_input").val('');
        }
                  
        });
                 
        return false;
    });
});

Upvotes: 1

Views: 158

Answers (5)

Robert Koritnik
Robert Koritnik

Reputation: 105059

You should provide functions instead of strings to setTimeout/setInterval functions. And also there's no need for you to set interval on window load event. You can just keep it as part of DOM ready:

$(function() {
    updateMessages(); // don't wait 2 seconds for first update
    setInterval(updateMessages, 2000); // update every 2 seconds
});

Everything else seems to should work as expected as long as your posback work when no data is being received (ref dataString).

I hope you do realise that you're using implied globals and understand why that may be a big problem (ref dataString again).

How I would rewrite your code

I would rewrite your whole code into the following that removes implied global variable dataString, doesn't pollute global scope with additional functions and uses setTimeout instead of interval which may in some cases be problematic (although in your case since it' only runs every 2 seconds it shouldn't be a problem if there's no additional very complex client-side script execution)

I've kept everything within function closure local scope:

$(function() {

    var timeout = null;

    var form = $("#mail_send").submit(function(evt){
        evt.preventDefault();
        $(".mail_conversation_answer_input", form).val("");
        updateMessages();
    });

    var updateMessages = function() {

        // we don'w want submit to interfere with auto-updates
        clearTimeout(timeout);

        $.ajax({
            type: "POST",
            url: "<?php echo site_url(); ?>mail/send",
            data: form.serialize(),
            success: function(data){
                $("#mail_container_conversation").html(data);
                timeout = setTimeout(updateMessages, 2000);
            }
        });
    };

    // start updating
    updateMessages();

});

This code requires your server side (processing on /mail/send) to understand that when nothing is being posted (no data) that it doesn't add empty line in the conversation but rather knows that this is just an update call. This functionality now uses only one server-side URL and not two of them. If you'd still require two, then this code should do the trick:

$(function() {

    var timeout = null;
    var url = {
        update: "<?php echo site_url();?>mail/ajaxupdate/<?php echo $user;?>",
        submit: "<?php echo site_url();?>mail/send",
        use: "update"
    };

    var form = $("#mail_send").submit(function(evt){
        evt.preventDefault();
        url.use = "submit";
        $(".mail_conversation_answer_input", form).val("");
        updateMessages();
    });

    var updateMessages = function() {

        // we don'w want submit to interfere with auto-updates
        clearTimeout(timeout);

        $.ajax({
            type: "POST",
            url: url[url.use],
            data: form.serialize(),
            success: function(data){
                $("#mail_container_conversation").html(data);
                url.use = "update";
                timeout = setTimeout(updateMessages, 2000);
            }
        });
    };

    // start updating
    updateMessages();

});

Upvotes: 2

Christofer Eliasson
Christofer Eliasson

Reputation: 33865

If the rest of your code work, the problem probably is withing this code:

$(document).ready(function() {
    var interval
    window.onload = function(){
        interval = setInterval('updateMessages()', 2000);
    };
});
  1. There is no need to attach it to window.onload, since you already wrapped it in a DOM-ready callback.
  2. Remove the single-quotes and the parenthesis from within your call to setInterval
  3. The DOM-ready callback can be shorten, by just passing a function to the jQuery-method.

Try this instead:

$(function () {
    setInterval(updateMessages, 2000);
});

Further improvements - Avoid intervals with AJAX:

When dealing with AJAX, you should avoid using intervals, as you may end up stacking calls to the server, if the server takes more than two seconds to respond. setInterval will not care if your server had time to respond or not, it will keep calling it every 2 seconds no matter what.

I suggest that you use a timeout instead, and start a new timeout in the complete-callback of the Ajax-call.

In your case, it could look something like this:

$(function () {
    // Make the first call immediately when the DOM is ready
    updateMessage();
});

function updateMessages() {
    $.ajax({
        type: "POST",
        url: "<?php echo site_url(); ?>mail/ajaxupdate/<?php echo $user; ?>",
        data: dataString,

        success: function(data){
            $("#mail_container_conversation").html(data);
            // Make a new call, 2 seconds after you've 
            // received a successful respose
            setTimeout(updateMessages, 2000);
        }        
    });
}

Upvotes: 2

Barmar
Barmar

Reputation: 781708

The problem is that updateMessages() tries to send datastring to the server, but this doesn't get filled in until the .submit() function runs.

I don't know what you should put in there, since I don't know what the mail/ajaxupdate script expects. If this is called when nothing happens, I suspect no form data is needed at all, so you can give an empty string.

I'll bet if you checked the Javascript console you'd see some error messages about trying to serialize undefined.

Upvotes: 1

minikomi
minikomi

Reputation: 8503

You don't need the window.onload in your document ready call.

$(document).ready(function() {
    setInterval('updateMessages()', 2000);
});

That should be enough to get it started.

As it is now, once the DOM is ready, you're then asking it to wait for the window to load.. but by that point it's already loaded, so nothing happens.

Upvotes: 0

Suresh Atta
Suresh Atta

Reputation: 122008

give a try with

$(document).ready(function() {

  setInterval('updateMessages()', 2000);

});

Upvotes: 0

Related Questions