Best ajax questions in June 2011

How to overcome this security issue

22 votes

I have implemented an ajax-polling script that calls an action in the server Controller every 10 seconds. With the response, I replace the content of a div:

function getFoo() {
    var link = '/Secure/GetFoo';

    $.post(link, function (response) {
        $('#FooSection').replaceWith(response);
    });

    setTimeout("getFoo();", 10000);
}

This is done through https. After some time of being "idle", IE displays the following message:

This page is accessing information that is not under its control. This poses a security risk. Do you want to continue?

If the user clicks Yes, the page is redirected to the div displaying the response only. If the user clicks No, nothing happens, but the div container will not be refreshed.

I know I can suppress this message through browser settings, but that will just bring me to a default Yes selection as per the above dialog.

A similar issue has been asked before, but unfortunately there hasn't been any solution. I basically want to make my ajax-polling work even on a secure connection. Any ideas?

You should never see that dialog on an Internet-Zone page. By default, this operation is silently and automatically blocked in the Internet Zone.

There are two root causes for that dialog to appear in the Intranet zone:

1> Attempting to do a cross-origin request using the XMLHTTPRequest object (http://blogs.msdn.com/b/ieinternals/archive/2011/04/22/ie-security-prompt-page-accessing-cross-domain-information-not-under-its-control.aspx)

2> Attempting to navigate an OBJECT Tag hosting HTML to a cross origin page.

You can avoid case #1 by using XDomainRequest instead of XMLHTTPRequest. You can avoid case #2 by using an IFRAME instead of an OBJECT tag.

Chrome AJAX on page-load causes "busy cursor" to remain

10 votes

In Google Chrome, AJAX called within $(function(){....}); seems to keep the page loading.

I have a site with a few pages with tabs. Because I'm using cheap godaddy hosting, I want the page to load as fast as possible. I thus want to load a page on 1 tab and then in the background use AJAX to load the other tabs. When I run AJAX from

$(function(){
    /*AJAX CODE HERE */
});

The cursor shows the page as loading for a long time (http://jsfiddle.net/mazlix/7fDYE/9/)

I have figured out a way (in chrome atleast) to somewhat fix that using setTimeout(); (http://jsfiddle.net/mazlix/7fDYE/8/), but this only works if you correctly predict when the window finishes fully loading and obviously makes it take longer to load. I want a way to load content via AJAX immediately after the page loads, so no "busy-cursor" is displayed while waiting for the returned AJAX.

Google Chrome shows Loading Indicator as long as there are no new queries to servers. While the loading indicator is shown, all new requests are causing Chrome to extend the time the indicator is shown. Furthermore, when esc is pressed while the indicator is shown, all requests are aborted! These include AJAX requests and even Flash requests! Take a look at this question: i thought it was because of Youtube, but it turned to be Chrome's usual behavior.

The only way to avoid "extending" the time Loading indicator is shown, is making the requests after the loading indicator is hidden: i.e. when all queries to server are completed. JQuery's documentation on .load() says:

The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object.

So, if you're sure that there are only images, scripts and frames on your page, window.load() will be fired just when you need it. Adding setTimeout() to it will work as you like. Here is an example: http://jsfiddle.net/7fDYE/22/

If there are other requests being made before your request, you should wait for them to be completed! For example, you know that besides the images/scripts etc. you have 3 more AJAX requests before the page loads. You can have something like this:

var loaded=0,needsToBeLoaded=4; //3 AJAX + window
function onLoad(){
    loaded++;
    if(loaded==needsToBeLoaded){
         //do the AJAX request   
    }
}
window.load(onLoad);
// add onLoad() to all 3 AJAX request handlers

I'm not sure what you can do with Flash requests...

AJAX and jQuery with MVC

8 votes

How do you organise your controllers, methods, views when you use a MVC model with jQuery with lots of AJAX bits?

Question 1

Do you have a seperate controller just for AJAX calls, or do you mix the AJAX methods together with your usual non-AJAX methods in one single controller?

Question 2

If you were to mix AJAX and non-AJAX methods in a single controller, do you have seperate AJAX and non-AJAX methods, or do you combine them together (if possible) and pass in a value (NULL or AJAX) which determines whether a normal view or a AJAX view is passed back to the browser.

Question 3

If you have 50 different AJAX calls, and each call requires a method, which in turn requires a view, we end up with a controller with 50 methods and 50 views. Is this good MVC practice? I can think of all AJAX methods in the controller sharing a single view, where the view file contains case conditional statements and the view file is passed a parameter which determines which of the 50 cases will be used. Kind of like compressing 50 views into 1.

Question 4

Instead of having so many views (50 views), what do you think of echoing the output in in the controller method rather than in the view? This way we won't have so many views.

BTW, I'm using CodeIgniter PHP framework for my MVC model

Question 1

I mix the ajax and non-ajax code in to the same controller. That way your code is in a common place easy to find.

Question 2

I combine ajax and non-ajax method together. Makes it easier to use javascript Progressive Enhancement so that people without javascript will still post to the same controller

Question 3

You should not have 1 controller with 50 methods. You should have a controller per piece of functionality. So a User Controller, a Foo controller, a Bar controller - so you may end up with 10 contollers with 5 methods each. This way methods belong in classes specific to their function. I have seperate views and not one big view. You should NOT use LOGIC inside views to determine what is shown, this is the job of the controller. But some controller/methods can return the same view as other methods

Question 4

Or controller should NEVER output HTML. Use views for this that is the whole pupose of MVC to seperate out Code (controllers from) Views (rendering) concerns. Some times my views just return JSON or XML and then I use Javascript templates to update the DOM. Othertimes my views return HTML. For example a Save function on a form. Might just return a Boolean if sucessful. Then my Javascript would hide or show a DIV depending on the response.

Possible collision of two ajax requests?!

7 votes

I'm having trouble with one of my sites on which two ajax requests are executed when the page loads. I'm using jQuery in combination with an PHP application based on the zend framework.

The relevant HTML (simplified) looks like:

<select id="first">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="first_block"></div>

<select id="second">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="second_block"></div>

Here is what my jQuery looks like:

$(document).ready(function(){

// function to update the first block
var updateFirstBlock = function(){
    var param = $(this).val();
    $.ajax('module/controller/action/param/' + param, {
        'success': function(data){
            $('.first_block').html(data);
        }
    });
};

// bind and trigger the first update function
$('select#first').bind('change', updateFirstBlock );
$('select#first').trigger('change');


// function to update the second block
var updateSecondBlock = function(){
    var param= $(this).val();
    $.ajax('module/controller/another-action/param/' + param, {
        'success': function(data){
            $('.second_block').html(data);
        }
    });
};

// bind and trigger the second update function
$('select#second').bind('change', updateSecondBlock );
$('select#second').trigger('change');

});

The PHP Application just returns some content dependent on which value is distributed.

Now what happens when the pages is loaded, is that in nine of ten cases one of the two requests gets no answer. The other one gets 200 OK and the failing one times out. There's no regularity, which request fails.

Is it possible that there's something wrong in the web-servers (Apache 2.2) configuration, so that two simultaneously fired requests constrain each other?

EDIT

If I set both requests to async: false, they are always executed properly. So there must be a collision, I think.

EDIT 2

A possible reason for this behavior, could be php's session lock. I will examine this further.

It seems your definitely on the right rack with the PHP session lock:

Session locking (concurrency) notes

The default PHP session model locks a session until the page has finished loading. So if you have two or three frames that load, and each one uses sessions, they will load one at a time. This is so that only one PHP execution context has write access to the session at any one time.

Some people work around this by calling session_write_close() as soon as they've finished writing any data to the $_SESSION - they can continue to read data even after they've called it. The disadvantage to session_write_close() is that your code still will lock on that first call to session_start() on any session'ed page, and that you have to sprinkle session_write_close() everywhere you use sessions, as soon as you can. This is still a very good method, but if your Session access follows some particular patterns, you may have another way which requires less modification of your code.

The idea is that if your session code mostly reads from sessions, and rarely writes to them, then you can allow concurrent access. To prevent completely corrupted session data, we will lock the session's backing store (tmp files usually) while we write to them. This means the session is only locked for the brief instant that we are writing to the backing store. However, this means that if you have two pages loading simultaneously, and both modify the session, the Last One Wins. Whichever one loads first will get its data overwritten by the one that loads second. If this is okay with you, you may continue - otherwise, use the session_write_close method, above.

If you have complicated bits of code that depend on some state in the session, and some state in a database or text file, or something else - again, you may not want to use this method. When you have two simultaneous pages running, you might find that one page runs halfway through, modifying your text file, then the second one runs all the way through, further modifying your text file, then the first one finishes - and your data might be mangled, or completely lost.

So if you're prepared to debug potentially very, very nasty race conditions, and your access patterns for your sessions is read-mostly and write-rarely (and not write-dearly), then you can try the following system.

Copy the example from session_set_save_handler() into your include file, above where you start your sessions. Modify the session write() method:

function write($id, $sess_data)
{
  global $sess_save_path, $sess_session_name;

  $sess_file = "$sess_save_path/sess_$id";
  if ($fp = @fopen($sess_file, "w")) {
   flock($fp,LOCK_EX);
   $results=fwrite($fp, $sess_data);
   flock($fp,LOCK_UN);
   return($results);
  } else {
   return(false);
  }

}

You will probably also want to add a GC (Garbage Collection) method for the sessions, as well.

And of course, take this advice with a grain of salt - We currently have it running on our testing server, and it seems to work OK there, but people have reported terrible problems with the Shared Memory session handler, and this method may be as unsafe as that.

You can also consider implementing your own locks for scary concurrency-sensitive bits of your code.

Ref: http://ch2.php.net/manual/en/ref.session.php#64525


It might be worthwhile implementing a database session handler. Using a database eliminates this problem and can actually improve performance slightly, if a good database structure is used.

Ajax navigation without #!

7 votes

I have noticed that sites like http://hypem.com which is a full ajax site have now managed to scrap their #! ajax urls but maintained a full ajax site. How is this possible?

You can do this with history.pushState, only in decent browsers though ;)

https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history

Here's a jQuery plugin with a fallback for older browsers to a hashed URL: http://plugins.jquery.com/project/history-js

Re-render Tweet button via JS

6 votes

I used to use this snippet to re-render a Tweet button (http://bit.ly/iqOhxm)

var tweetButton = new twttr.TweetButton(twitterScript);
twttr.render();

But it looks like widgets.js (http://platform.twitter.com/widgets.js) has been modified so twttr.TweetButton is no longer a constructor.

Can anyone help with this issue?

Looks like the twttr.TweetButton constructor was never supported, and now no longer works after the last API update:

The supported method is to create an iframe-based Tweet button dynamically:

How to avoid unnecessary buffering in jPlayer

6 votes

I have a jPlayer (HTML5 song player using jquery) and it starts to play a song from xx secs of a song.

But the problem is it has to first buffer the XX secs and then starts to play which is waste of bandwidth. Why doesnt it start its buffering from XX secs itself?

Here is the code i use:

$("#jquery_jplayer_1").jPlayer({
        ready: function () {
          $(this).jPlayer("setMedia", {
            mp3: playList[0],
            volume: CUR_VOL
          }).jPlayer("play", 251);
        },
        swfPath: "js",
        supplied: "mp3",
        errorAlerts: false
      });

EDIT

I wanted an answer for avoiding the buffering of first XX seconds.

It's the flash polyfill that needs to buffer. Older browsers that do not support HTML5 <audio> will suffer from this problem, where the jPlayer flash fallback used instead.

Your web server must support seeking a stream.

See this jPlayer Google Group question about buffering and Seeking through a streamed MP3 file with HTML5 <audio> tag & https://groups.google.com/forum/#!topic/jplayer/irSrmN0aUSU for a discussion on seeking and Accept-Ranges headers.

Edit: I've done some digging into this problem… although I'm sorry that I still do not have a final answer.

Firstly, the jPlayer Development Guide details the issues with .mp3 files and the Accept-Ranges header. If you use Chrome you can actually see the Accept-Ranges request and response header - if you press F12 and select the Network tab. Clicking on the .mp3 file, you can inspect the headers. The good news is that is does look like your server does support the Accept-Ranges header. However, it still does not explain why sometimes it needs to buffer the download first.

I think you should start with a simple demo, with no flash support and a single .mp3. Your playlist is randomly generated so it is difficult to determine if the problem is only for certain files. Also, I have used the jPlayer Inspector which can give detailed statistics for jPlayer which may help to diagnose the problem.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>Test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
    <script src="jQuery.jPlayer.2.0.0/jquery.jplayer.min.js" type="text/javascript"></script>
    <script src="jQuery.jPlayer.2.0.0/jquery.jplayer.inspector.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function(){
            $('#jplayer').jPlayer({
                ready: function () {
                    $(this).jPlayer('setMedia', {
                        mp3: 'mp3/example.mp3'
                    });
                },
                swfPath: 'not_a_valid_directory',
                solution: 'html, flash',
                supplied: 'mp3'
            });

            $('#jplayer_inspector').jPlayerInspector({jPlayer:$('#jplayer')});

            $('#seeker').click(function() {
                $('#jplayer').jPlayer('play', 20);
                return false;
            });
        });
    </script>
</head>
<body>
<div id="jplayer"></div>
<a href="#" id="seeker">Play 20s from start</a>
<div id="jplayer_inspector"></div>
</body>
</html>

You could also change the demo code above to include:

swfPath: 'jQuery.jPlayer.2.0.0',
solution: 'flash, html',

in the jPlayer constructor to force Flash to be the default player.

Waiting for jQuery AJAX response(s)

5 votes

I have a page that, using jQuery .ajax that is called 100 times (async: true), the problem is that, when they they are all being loaded, I need the system to wait for ALL 100 calls to return before continuing. How would I go about this?

Thanks in advance! :)

Update:

These calls are made in a for() loop (there's 100 of them :))

The nice way to do this is with $.when. You can use this as follows:

$.when(
    $.ajax({/*settings*/}),
    $.ajax({/*settings*/}),
    $.ajax({/*settings*/}),
    $.ajax({/*settings*/}),
).then(function() {
    // when all AJAX requests are complete
});

Alternatively, if you have all the AJAX calls in an array, you could use apply:

$.when.apply($, ajaxReqs);

Note that this requires at least jQuery 1.5.


To add the AJAX requests to an array, do something like this:

var ajaxReqs = [];
for (var i = 0; i < 100; i++) {
    ajaxReqs.push($.ajax({
        /* AJAX settings */
    });
}
$.when.apply($, ajaxReqs).then(function() {
    // all requests are complete
});

Why use a form tag when you're submitting via ajax?

5 votes

Philosophical question:

Say I've got a web app that requires javascript and a modern browser, so progressive enhancement is not an issue. If my form is being built via javascript, and my data updates are all being done via ajax POSTs & PUTs, is there really any reason to wrap my controls in a form tag? If I'm still going to use the tag, say for semantic or structural reasons, is there any reason to have action and method params that I'm going to ignore? It kind of feels like a hold-over from an earlier era to me.

There is at least one important user-experience feature provided specifically by wrapping inputs inside a form tag:

The enter key will submit the form. In fact, in Mobile Safari, this is how you get the "Go" button to appear on the keyboard.

Without a form wrapping the inputs, there is nothing to submit.

You can of course provide enter-key behavior through a keypress event, but I don't know about if this works for mobile devices. I don't know about you, but I'd rather work with the semantics provided by the browser than have to imitate them with events.

In your case, you would simply provide an onsubmit event handler for the form, which would do your AJAX submit, then return false, canceling the actual submit.

You can simply provide action="" (which means "self"), and method is not required — it defaults to GET.