Best ajax questions in October 2010

How does facebook rewrite the source URL of a page in the browser address bar?

38 votes

Go to http://www.facebook.com/facebook?v=wall, then click on the info tab. The content will be loaded, and the address bar now becomes http://www.facebook.com/facebook?v=info but the webpage didn't reload.

At first I think it is Ajax, but my question is, how do you change the address bar without reloading? I know I can change anchor (#wall) using JS but querystring (?v=wall), how?

It's using HTML5's new history.pushState() feature to allow the page to masquerade as being at a different URL to that from which it was originally fetched.

This seems only to be supported by WebKit at the moment, which is why the rest of us are seeing ?v=wall#!/facebook?v=info instead of ?v=info.

The feature allows dynamically-loaded pages to be properly bookmarked, exchanged etc between JS-supporting and non-JS-supporting user agents. Because if you as a JS user linked someone to ?v=wall#!/facebook?v=info and their browser didn't support JS and XMLHttpRequest, the page wouldn't work for them. The #! is also used as a tip to search engines to download the non-AJAX version.

Why do we not see much AJAX in secure applications like internet banking?

12 votes

Can someone list with references / evidences if possible, why we don't see much AJAX in secure web applications like internet banking?

eg. Internet banking has a list of tabs for Accounts, Payments, Tools, Reports. Normally you'd see these implemented as links to different pages. Why couldn't you just have one page and use AJAX to load the content of the different tabs? (eg. a JSF RichFaces tab control)

I'm assuming that bookmarking and handling the back button (or disabling it as is common for internet banking) for the different URLS will be handled in either scenario. So I'd like to hear other things, like how it could affect security, performance etc?

My team is about to start building a web based payment management system (think setting up payments, managing client account balances, reconciliation etc.). Its not going to be making the actual payments, but it will at some point integrate with a leading bank's internet banking system.

We're divided over using one page and using AJAX for everything else

or

using AJAX only where its really helping user experience.

Ajax can improve usability but adds complexity.

Banks need security.

Complexity is the enemy of security.

Therefore Ajax is the enemy of Banks ;)

Options for ASP.NET page with matching client-side and server-side markup?

12 votes

Suppose I'm building a StackOverflow clone using webforms ASP.NET and jQuery. The Question page has a question, several answers, and comments under each. Requirements:

  1. Users can post new answers and comments, and edit existing ones, without postbacks.
  2. No UpdatePanels; the AJAX calls retrieve just the JSON they need, not HTML fragments.
  3. The page loads with all existing answers and comments in place (no javascript needs to run to read the page).

What I'm trying to figure out is how to do this without having to maintain two sets of markup (one that's bound on the client using some form of jQuery templating, and one that's bound on the server using traditional WebForms).

What are my options?

While it is not exactly what you asked for you may want to consider rendering the HTML on the server via a service (not using update panel) and sending it to the client instead of using client templates. It couldn't be that bad because Facebook are doing it: http://www.facebook.com/video/video.php?v=596368660334 If it is suitable in your situation depends on how rich your markup is and what percentage of the data sent over the wire will be markup as opposed to content.

using slick upload with mvc 2 and jquery / ajax

7 votes

i'm trying to get slick upload working inside a jquery ui dialog. I've got it uploading the file just fine, and i've checked out the samples, and they all end up with the entire page re-loading. i've managed to make it so it doesn't do it's final postback to deal with the files after it uploads by setting the AutoPostBackAfterUpload="false"

so it now puts the files on the server, with the random guid name. and it get's a response that looks like this:

{
state : "Complete",
reason : "NotTerminated",
percentComplete : 100.00,
percentCompleteText : "100.00 %",
contentLengthText : "826 KB",
transferredLengthText : "826 KB",
remainingLengthText : "0 bytes",
currentFileName : "Desert.jpg",
currentFileIndex : "1",
timeElapsedText : "1 second",
timeElapsedShortText : "00:01",
timeRemainingText : "",
timeRemainingShortText : "00:00",speedText : "596 KB/sec"
}

so what i need to know is: how do i ajaxly post what slick upload does automatically when you have the AutoPostBackAfterUpload set to true.

here's my code: <% Html.BeginForm("OrganizationMemberEditContactSectionChangePhoto", "OrganizationMember", FormMethod.Post, New With {.id = "uploadForm", .enctype = "multipart/form-data"})%>

    <kw:SlickUpload ID="SlickUpload1" runat="server" AutoPostBackAfterUpload="false"  UploadFormId="uploadForm" ShowDuringUploadElements="cancelButton" HideDuringUploadElements="uploadButton" MaxFiles="1" AutoUploadOnPostBack="false" ProgressInterval="200">
        <DownlevelSelectorTemplate>
            <input type="file" />
        </DownlevelSelectorTemplate>
        <UplevelSelectorTemplate>
            <input type="button" value="Add File" />
        </UplevelSelectorTemplate>
        <FileTemplate>
            <kw:FileListRemoveLink runat="server">[x] remove</kw:FileListRemoveLink>
            <kw:FileListFileName runat="server" />
            <kw:FileListValidationMessage runat="server" ForeColor="Red" />
        </FileTemplate>
        <ProgressTemplate>
            <table width="99%">
                <tr>
                    <td>
                        Uploading <kw:UploadProgressElement ID="UploadProgressElement1" runat="server" Element="FileCountText" />,
                        <kw:UploadProgressElement ID="UploadProgressElement2" runat="server" Element="ContentLengthText">(calculating)</kw:UploadProgressElement>.
                    </td>
                </tr>
                <tr>
                    <td>
                        Currently uploading:
                        <kw:UploadProgressElement ID="UploadProgressElement3" runat="server" Element="CurrentFileName" />,
                        file <kw:UploadProgressElement ID="UploadProgressElement4" runat="server" Element="CurrentFileIndex">&nbsp;</kw:UploadProgressElement>
                        of
                        <kw:UploadProgressElement ID="UploadProgressElement5" runat="server" Element="FileCount" />.
                    </td>
                </tr>
                <tr>
                    <td>
                        Speed:
                        <kw:UploadProgressElement ID="UploadProgressElement6" runat="server" Element="SpeedText">(calculating)</kw:UploadProgressElement>.
                    </td>
                </tr>
                <tr>
                    <td>
                        About
                        <kw:UploadProgressElement ID="UploadProgressElement7" runat="server" Element="TimeRemainingText">(calculating)</kw:UploadProgressElement> remaining.
                    </td>
                </tr>
                <tr>
                    <td>
                        <div style="border: 1px solid #008800; height: 1.5em; position: relative">
                            <kw:UploadProgressBarElement ID="UploadProgressBarElement1" runat="server" Style="background-color: #00ee00; width: 0; height: 1.5em" />
                            <div style="text-align: center; position: absolute; top: .15em; width: 100%">
                                <kw:UploadProgressElement ID="UploadProgressElement8" runat="server" Element="PercentCompleteText">(calculating)</kw:UploadProgressElement>
                            </div>
                        </div>
                    </td>
                </tr>
            </table>
        </ProgressTemplate>
    </kw:SlickUpload>
    <p>
        <input type="button" value="Upload" id="uploadButton" />
        <a href="javascript:kw.get('<%=SlickUpload1.ClientID %>').cancel()" id="cancelButton" style="display:none">Cancel</a>
    </p>            
<%Html.EndForm()%>
<script type="text/javascript">
    var theThing;
    var urlToPost = "theUrlThatHandlesThePostBack";
    function v2SetUpPhotoDialog() {

        theThing = kw.get("<%=SlickUpload1.ClientID %>");
        theThing.add_OnUploadEnded(function (status) {
            var data = $('#uploadForm').serialize();
            $.ajax({
                type: 'POST',
                url: urlToPost,
                data: data,
                success: function () {
                    v2RegularNotice('success');
                },
                error: function () {
                    v2RegularNotice('fail');
                }
            });
        });

        $('#uploadButton').live('click', function () {
            theThing = kw.get("<%=SlickUpload1.ClientID %>");
            theThing.submit();
            return false;
            //  kw.get("<%=SlickUpload1.ClientID %>").submit();
        });
    }
</script>

as you can see, i tried having the OnUploadEnded take the status as a parameter, but it doesn't fill it with any of the useful information that the status parameter for the action needs. It currently serializes the form and sends that, but it only populates 1 field. kw_uploadId.

the controller action doesn't do anything yet, it just tries to take a UploadStatus as a parameter. but it's empty if i just serialize the form.

i'm sure i'm missing something obvious. but i can't figure it out. i'm finding the documentation kind of hard to follow and not to helpful in this case.

thanks!

After working with Patrica, this issue has been solved. We ran into a couple more snags, but the basics are as follows:

The main thing at work here is a limitation in SlickUpload's design: you can't remove a SlickUpload control from the DOM once it's been added and then readd it again later. This will be solved in SlickUpload6, but is unfortunately a limitation with the current version. To solve this, we hid the control when the tab or dialog was invisible, instead of actually removing it.

There is also a SlickUpload minor version release (5.5.9) that adds a get_UploadId() method, to make getting the upload id for the current upload easier.

This code (from above):

kw_uploadId: document.getElementById("kw_uploadId").value,

becomes:

kw_uploadId: theThing.get_UploadId(),

You can get the latest version here: SlickUpload 5.5.9

Implementing a random chat among people

6 votes

My idea is to make a website, where people could registry and search for a people to talk. They can choose people from certain country, genre, with certain age and so on.

Yeah, I know there is a lot of websites like this, but I want to implement this, because it looks really challenging.

Can you give me ideas how could I implement this using PHP + MYSQL + Jquery(Ajax)? I am neither a beginner nor advanced with these things.

So, how should this work? One person clicks search button, this person is put in database that he searches for somebody to talk, so what's next? I also want to be able to allow people to talk with a few people at the same moment.

I am not asking for a code or something, just ideas how to code it, no code needed.

Thank you.

I don't think that a synchronous, blocking programming language like PHP is the right platform for such an application. It were much wiser to choose an asynchronous, non-blocking language like JavaScript. This has the great advantage that you may use Long Polling which will improve the chatting experience in your application.

Thus I recommend implementing this using NodeJS. You may want to look at an implementation of a simple chat in node.

Best method to prevent gaming with anonymous voting

6 votes

I am about to write a voting method for my site. I want a method to stop people voting for the same thing twice. So far my thoughts have been:

  • Drop a cookie once the vote is complete (susceptible to multi browser gaming)
  • Log IP address per vote (this will fail in proxy / corporate environments)
  • Force logins

My site is not account based as such, although it aggregates Twitter data, so there is scope for using Twitter OAuth as a means of identification.

What existing systems exist and how do they do this?

The best thing would be to disallow anonymous voting. If the user is forced to log in you can save the userid with each vote and make sure that he/she only votes once.

The cookie approach is very fragile since cookies can be deleted easily. The IP address approach has the shortcoming you yourself describe.

How to make facebook like private message

6 votes

When you send a private message to someone on FB in the TO field when typing the first letter a suggestion appears then it becomes a little box with the name of the user you selected which can be deleted, anyone got a tutorial on this? thanks

This looks like it'll do the trick.

"Redirect" page without refresh (Facebook photos style)

6 votes

I am trying to implement content browsing like it is done on Facebook when user is browsing the photos. I guess everyone is familiar with that photo browsing where you can click "next" and "previous" and immediately get the next or previous photo (you can also navigate using arrow keys).

When you click "next" for example you notice that the page does not refresh - only the content. At first I thought it is done using plain ajax calls which refresh only the "content" in this case the image, description and comments. But then I noticed that also URL in the "Location" toolbar of my browser is changed! I tried to inspect this using Firebug and discovered that when you click "next" only the next photo is downloaded and I still don't know from where the comments & image meta data (description, time, tags,...) are loaded.

Can someone please explain how this technique is done - page URL changes without page refresh (or even without page "blinking" if it refreshes from cache). I know how to change page content using ajax but URL of that page stays the same all the time. If I click on "refresh" button I get the first page again. But not on Facebook since even the "window.location" is changed every time without actual redirect.

The other thing I noticed is that the bottom toolbar (applications, chat, ...) is "always on top". Even if you change the page, this toolbar is not refreshed and always stays on top - it doesn't even "blink" like other pages that are refreshed (either from webserver or from local cache). I guess this is the same technique as above - some kind of "fake" redirects or something?

The Answer is pushState

if (window.history.pushState)
    window.history.pushState([object or string], [title], [new link]);

You will smile :)

I've tried to change through facebook images, and this is what I saw:

In Firefox:

The page URL is not changing. Only the hash is changing. This is a technique used to allow crawlers to index the content. What happens is this:

  • User clicks on "next"
  • JS loads the next image with tags, comments, etc and replaces the old content with them.
  • JS changes the hash to correspond the new image

urls look like this: http://www.facebook.com/home.php?#!/photo.php?fbid=1550005942528966&set=a.1514725882151300.28042.100000570788121&pid=3829033&id=1000001570788121 (notice the hash)

As for the second question, this is just a benefit of the technique above. When you are on facebook, the page rarely gets actually refreshed. Only the hash is changed so that you can send links to other people and crawlers can index the content.

In Google Chrome:

It seems that chrome hassome way to change urls without refreshing the page. It does that by using window.history.pushState. Read about it here.

urls look like this: http://www.facebook.com/photo.php?fbid=1613802157224343&set=a.1514725288215100.28042.1000005707388121&pid=426541&id=1000001570788121 (notice that there is no hash here, but still the url is changing along with images)

In Epiphany:

Epiphany doesn't change the URL when the image changes.

urls look like this: http://www.facebook.com/photo.php?fbid=1441817122377521&set=a.1514725882215100.28042.1000005707848121&pid=3251944&id=1000200570788121 (there is no hash, and the URL stays the same when changing the image)

(don't have other browsers to verify right now)

Load local JSON files via file:// triggers cross-domain null origin violation, solution? (jQuery)

5 votes

I have a webpage I'd like to use locally, without a web server, by simply opening the local HTML file in my browser. This webpage in question loads data via jQuery's getJson() method, as in:

$.getJSON("mydata.json", function(j) { 
...

The JSON files are also local, and are stored in the same directory as the webpage. When I attempt to use the page, I get:

Origin null is not allowed by Access-Control-Allow-Origin.

(Chrome 6 OS X, similar errors in Firefox and Safari).

Is there any way around this? Is it possible to load JSON from local files? Thanks!

Try running Chrome with --allow-file-access-from-files.

How do you call a JavaScript (AJAX) function when the user reaches the end of a page to load new content?

5 votes

On twitter (new twitter) and facebook they now have the the ability to load new tweets and posts when you hit the bottom of the page..

Is there a JavaScript / jQuery event that you can call / add to a div so when the browser hits the bottom it does some ajax call to get the new data?

Thanks

Daniel

There's a jQuery plugin for that: Infinite Scroll jQuery Plugin.

And here's the description of the pattern that it implements: The Interaction Design Pattern.

Ajax pagination like Twitter

5 votes

Is there any plugin/gem or an easy way for accomplish a pagination functionality like Twitter?

This means, showing a "More" button that shows more posts (for example) below once it's clicked, using Ajax.

If there's any easy way for modifying something from will_paginate plugin, that would be useful too.

I use this for easy pageless pagination. Seems to be a better solution w/o the more button.

http://github.com/jney/jquery.pageless

Using HTML5 file uploads with AJAX and jQuery

5 votes

Admittedly, there are similar questions lying around on SO. But it seems none quite meet my requirements. Here is what I'm looking to do:

  • Upload an entire form of data, one piece of which is a single file
  • Work with Codeigniter's file upload library

Up until here, all is well. The data gets in my database as I need it. Good good. But I'd also like to submit my form via an AJAX post:

  • Using the native HTML5 File API, not flash or an iFrame solution
  • Preferably interfacing with the low-level .ajax jQuery method

I think I could imagine how to do this by auto-uploading the file when the field's value changes using pure javascript, but I'd rather do it all in one fell swoop on for submit in jQuery. I'm thinking it's not possible to do via query strings as I need to pass the entire file object, but I'm a little lost on what to do at this point. Am I chasing a unicorn here?

Thanks so much for any help you could give.

It's not too hard. Firstly, take a look at FileReader Interface.

So, when the form is submitted, catch the submission process and

var file = document.getElementById('fileBox').files[0]; //Files[0] = 1st file
var reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = shipOff;
//reader.onloadstart = ...
//reader.onprogress = ... <-- Allows you to update a progress bar.
//reader.onabort = ...
//reader.onerror = ...
//reader.onloadend = ...


function shipOff(event) {
    var result = event.target.result;
    var fileName = document.getElementById('fileBox').files[0].name; //Should be 'picture.jpg'
    $.post('/myscript.php', { data: result; name: fileName; }, continueSubmission);
}

Then, on the server side (i.e. myscript.php):

$data = $_POST['data'];
$fileName = $_POST['fileName'];
$serverFile = time().$fileName;
$fp = fopen('/uploads/'.$serverFile,'w'); //Prepends timestamp to prevent overwriting
fwrite($fp, $data);
fclose($fp);
$returnData = array( "serverFile" => $serverFile );
echo json_encode($returnData);

Or something like it. I may be mistaken (and if I am, please, correct me), but this should store the file as something like 1287916771myPicture.jpg in /uploads/ on your server, and respond with a JSON variable (to a continueSubmission() function) containing the fileName on the server.

Check out fwrite() and jQuery.post().

On the above page it details how to use readAsBinaryString(), readAsDataUrl(), and readAsArrayBuffer() for your other needs (e.g. images, videos, etc).

Web sockets make ajax/CORS obsolete?

5 votes

Will web sockets when used in all web browsers make ajax obsolete?

Cause if I could use web sockets to fetch data and update data in realtime, why would I need ajax? Even if I use ajax to just fetch data once when the application started I still might want to see if this data has changed after a while.

And will web sockets be possible in cross-domains or only to the same origin?

WebSockets will not make AJAX entirely obsolete and WebSockets can do cross-domain.

AJAX

AJAX mechanisms can be used with plain web servers. At its most basic level, AJAX is just a way for a web page to make an HTTP request. WebSockets is a much lower level protocol and requires a WebSockets server (either built into the webserver, standalone, or proxied from the webserver to a standalone server).

With WebSockets, the framing and payload is determined by the application. You could send HTML/XML/JSON back and forth between client and server, but you aren't forced to. AJAX is HTTP. WebSockets has a HTTP friendly handshake, but WebSockets is not HTTP. WebSockets is a bi-directional protocol that is closer to raw sockets (intentionally so) than it is to HTTP. The WebSockets payload data is UTF-8 encoded in the current version of the standard but this is likely to be changed/extended in future versions.

So there will probably always be a place for AJAX type requests even in a world where all clients support WebSockets natively. WebSockets is trying to solve situations where AJAX is not capable or marginally capable (because WebSockets its bi-directional and much lower overhead). But WebSockets does not replace everything AJAX is used for.

Cross-Domain

Yes, WebSockets supports cross-domain. The initial handshake to setup the connection communicates origin policy information. The wikipedia page shows an example of a typical handshake: http://en.wikipedia.org/wiki/WebSockets

Form loses ability to send POST requests after 2 ajax updates

4 votes

I have an included object's form:

<form method="post" class="object_form" id="event-core-form" action="{% url save_event_core_data event.id %}" enctype="multipart/form-data">
    {{ form.as_p }}
    <p>
        <input class="object-submit" id="object-data-save" type="submit" value="Save data">
    </p>
</form>

After hitting 'submit' button I'm running this script, which submits my form via ajax, updates data and should return updated form that will be inserted back in it's place:

$("#object-data-save").livequery("click", function(e) {
    e.preventDefault();
    $(this).parents("form:first").ajaxSubmit({
        data: {"action": action},
        "success": function(data) {
            data = JSON.parse(data);
            $("#core-data").html(data["html"]);
            $("#message").show();
            $("#message").fadeIn(400).html('<span>'+data["message"]+'</span>');
            setTimeout(function(){
                $("#message").fadeOut("slow", function () {
                    $("#message").hide();
                });

            }, 1500);                
        }
    });
    return false;
});

and this runs the following function :

def event_core_data(request, event_id):
    template_name="management/core_event.html"    
    event = Event.objects.get(pk=event_id)
    form = EventForm()

    if request.method == "POST":
        form = EventForm(instance=event, data=request.POST)
        message = _("Error saving data")
        if form.is_valid():
            form.save()
            message = _(u"Data saved.")

        html =  render_to_string(template_name, RequestContext(request, {
            "form" : form,
            "event" : event,
        }))

        result = simplejson.dumps({
            "html" : html,
            "message" : message,
        }, cls = LazyEncoder)

        result = HttpResponse(result)
        logging.debug(result)
    else:
        form = EventForm(instance=event)
        result = ""
        try:
            result = render_to_string(template_name, RequestContext(request, {
                "form" : form,
                "event" : event,
            }))
        except:
            pass

    return result

After saving it once everything works as expected. But after third update my form is not inserted in the parent template. Instead I'm redirected to the edit function's url and the form is rendered as a raw html. Also, I've noticed in firebug, that when I'm being redirected - no POST is sent and a dummy 'alert' in my javascript is not fired. This is the function displaying initial state (if it's of any help):

def manage_event(request, event_id,):
    template_name = 'management/edit_event.html'

    try:
        event = Event.objects.get(pk=event_id)
    except DoesNotExist:
        url = reverse("manage_events")
        return HttpResponseRedirect(url)

    return render_to_response(template_name, RequestContext(request, {
        "core_data" : event_core_data(request, event_id),
        "event" : event,
    }))

EDIT

Here is a test link to this project, where you can see what's going on. 'event_core_data' returns the request.POST to console upon successfull update.

http://ntt.vipserv.org/manage/events/2

I'm also wondering why my date picker widgets disappear after submission. Are those things somehow connected together ?


EDIT 2

I've already tried using .post or .ajax instead of .ajaxSubmit but without any luck.

First of all, you're doing something slightly weird. You use a jQuery-plugin which is supposed to handle form submission over ajax and repopulate the fields. Still, on success, you replace all the HTML of your form with HTML from the server, negating its work.

This breaks your calendar/time widgets, as you initialize the widgets on page load, telling them to act on some page elements, which you later replace.

But this doesn't by itself break the form submission.

Firstly, you don't need a plugin for attaching events "live" if you stop replacing the form HTML. Secondly, you don't really need a plugin for that anyway as it seems the built-in live() method in jQuery should do the job (that is, if you actually do need this functionality). Thirdly, if you use plugins and they don't seem to be working properly, update to the latest version. The version you're using doesn't support the html() method in jQuery.

The livequery-plugin does its magic by overriding any jQuery-methods which might update the DOM. So when the programmer calls, f.ex, append(), it intercepts the call, calls append() for you, and then checks the document for new or disappeared elements matching your provided selector. The version you're using is not aware of html() and therefore does not intercept it.

So it works the first time as you initiate a DOM-check on page load. When that result is returned, the event is actually attached to the new submit-button because the calls to html() to set the new form and completion-message internally calls intercepted methods. Therefore, the second submission works as desired. But when the second call comes back, a jQuery cache is used internally, not calling any intercepted methods. So the event doesn't get attached to the submit-button, making it act as a regular form submission button.

To fix, stop using live-attaching for event-listening if there's not a non-apparent need for it. If there is, use the built in one or at least update your livequery plugin. Also, don't replace the whole form HTML. Again, if there's a non-apparent reason, re-initialize you calendar widget each time after setting the HTML.