views:

904

answers:

7

What I want is to have links which change a part of the page , and a dynamic URL for it, where I can specify variables such like #calendar=10_2010tabview=tab2

Check this for an exact example: CLICK HERE FOR EXACT DEMO

So here is the link format what I need:

#calendar=10_2010&tabview=tab2

I need to have variables in the links like calendar and tabview so I can change multiple things on a single page without realoading.


Or another format such like on http://www.wbhomes.com.au , this is exactly what I want, however the first format is good too but this is much more beautiful.

  • http://wbhomes.com.au/#/propertiesforsale/houseandland/quinnsbeach-waterland1

Requirements

  • Needs to be accessed from anywhere from example a mail, or if I just write in the url bar.

  • The link should be in the history, so if If I push the back or forward button the page needs to be accessed.

  • Page refresh needs to work too.


Some recources:

Examples:

Some Tutorials:


Please help me! I've never found any solution to do this, but I don't want to use jquery or any API, or any library, I want to have a working Javascript/AJAX and PHP script.

+1  A: 

Szevasz.. :)

HTML

<a href="/bye.php?user=abc&page=messages" 
   onclick="return goToWithAjax(this);">bye</a> 

Javascript

function goToWithAjax(hash) {
  hash = hash.href ? hash.getAttribute("href", 2) : hash;
  ajax( hash, function( response ) {
    document.getElementById("content").innerHTML = response;
  });
  hash = ("#!/" + hash).replace("//","/");
  window.location.hash = hash;
  return false;
}

//////////////////////////////////////////////////////////////////////////////

function getXmlHttpObject() {
    var xmlHttp;
    try {
        // Firefox, Opera 8.0+, Safari
        xmlHttp = new XMLHttpRequest();
    } catch (e) {
        // Internet Explorer
        try {
            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
    }
    if (!xmlHttp) {
        alert("Your browser does not support AJAX!");
    }
    return xmlHttp;
}

function ajax(url, onSuccess, onError) {
    var xmlHttp = getXmlHttpObject();
    xmlHttp.onreadystatechange = function() {
        if (this.readyState === 4) {
            // onSuccess
            if (this.status === 200 && typeof onSuccess == 'function') {
                onSuccess(this.responseText);
            }
            // onError
            else if(typeof onError == 'function') {
                onError();
            }
        }
    };
    xmlHttp.open("GET", url, true);
    xmlHttp.send(null);
    return xmlHttp;
}​
galambalazs
Hey there @galambalazs, thanks for the script, I will test it! Szevasz :D
CIRK
And what if I have something before the #hello? example: example.com/?ice=cream#best
CIRK
see my update, now you've got a pretty generic solution. :) You can use file names, or urls with hashes. You can also specify the file extension in that case, which is php by default.
galambalazs
The URL is not changing. :S here is how I used it: `<a href="http://192.168.2.104/?user=<?php echo $user->username?>#messages" onclick="return goToWithAjax('http://192.168.2.104/pages/messages.php');">messages</a>`
CIRK
it works as expected then?
galambalazs
Umm.. no, as I said the `URL` is not changing when I `click` on the `link`. But the content is changing :)
CIRK
Alright, let's get this straight. You can only change the url's hash part if you want to stay in the same page. `<a href="#messages" onclick="goToWithAjax(this)">messages</a>`. So you can't change what's in the URL bar except the `#hash` part, because if you do you will redirect the user to another page (and you break the essence of ajax)
galambalazs
What facebook is doing is this `http://www.facebook.com/#!/home.php?sk=bd` it's quite different than what you've asked for
galambalazs
if I write `onclick="goToWithAjax(this)`, nothing happens, the content remains blank and the `URL` is not changing too.
CIRK
Well, I mean how it works, without knowing any background stuff, when you click on the link the `URL` is changing and the `content` part too, everything else remains the same. this is what I want too. `http://192.168.2.104/?user=galambalazs#messages`
CIRK
But then you open messages.php, but it aint gonna know what user is selected on the page. Because they are two separate requests.
galambalazs
then how should I do it?
CIRK
I want to have later the message id to, how should I do that too, for me the facebook's version is good to since that's perfect, but how can I make that?
CIRK
I've updated the answer.
galambalazs
Úristen! It works! but this is how the `URL` looks like after I click on it: `http://192.168.2.104/?user=Adam#/#!/http:/192.168.2.104/pages/messages.php?user=Adam">messages</a>`, what's the problem ?
CIRK
Or this is the way you created it? to take the full url?
CIRK
and something else, In my base question , I wrote that the `URL` must be accessed from anywhere, from a mail or if I write it manually, this is not working here :S
CIRK
umm and reload doesn't works too :S, but I'm really really happy that the content+url is changing too :D
CIRK
You need to handle those things on the server-side(PHP). This is what facebook does. So you take `$_SERVER['REQUEST_URI']`, sth like: `$hash = array_pop(explode('#', $_SERVER['REQUEST_URI']));`, then you've got the AJAX part of the URL and you can load the content accordingly.
galambalazs
CIRK
no `$hash` will contain the AJAX part of the url, like `home.php?user=galambalazs`, and by knowing that you can generate the content.
galambalazs
so where should I put the `$hash`? in the `messages.php` or where?
CIRK
into every site you do ajax. This will help you to recover ajax things. Like when the user comes from a link.
galambalazs
Ahh na ezt magyarul :D Mostmár megkerdülök itt mert nem értem. xD Nem értem hogy hogyan kell használni a `$hash`-t, a file amit megkéne hívjon az `ajax` az a `messages.php`, azokba a fileokba kéne rakjam amiket meghív az `ajax`? és ha igen akkor ott mit csináljak vele?
CIRK
@cir: Could you keep it english so other people can follow?
Georg Fritzsche
@George Fritzsche, of course, here is what I saied: I don't understand how to use the $hash, the file what the `ajax` needs to include is `messages.php`. Do I need to put the `$hash` to the files what the `ajax` invites? if yes then what should I do with that?
CIRK
+11  A: 

For the demo linked in your question, achieving that functionality is actually really simple - as it doesn't use any AJAX at all (when you start to add AJAX to the mix, it get's more difficult - explained later). To achieve that functionality you would; upgrade your links to use hashes, then bind into the hashchange event. Unfortunately the hashchange event is not cross-browser compatible, though luckily there are many "history/remote plugins" available - our preferred one over the years has proven to be jQuery History, it's open-source, got great support and is actively developed :-).

Although, when it comes to adding AJAX functionality to the mix like such sites as Facebook, WBHomes and Balupton.com then you will start to face a whole series of seriously difficult problems! (I know as I was the lead architect for the last two sites!). Some of these problems are:

  • How to gracefully and easily upgrade certain internal links to use the History and AJAX functionality, and detect when the hash has changed? while keeping other links working just like before.
  • How to redirect from "www.yoursite.com/myapp/a/b/c" to "www.yoursite.com/myapp/#/a/b/c"? and still keep the experience smooth for the user such that the 3 necessary redirects are as smooth as possible.
  • How to submit form values and data using AJAX and update the hash? and vice versa if they don't support Javascript.
  • How to detect which particular area of the page the AJAX request is wanting? Such that subpages are displayed with the correct page.
  • How to change the page title when the AJAX state changes? and other non-page content.
  • How to perform nice intro/outro effects while the AJAX state loads and changes? such that the user isn't left in the dark.
  • How to update the sidebar login info when we login via AJAX? As obviously we don't want that login button up the top left to be there anymore.
  • How to still support the website for users that do not have JS enabled? Such that it gracefully degrades and still is indexable by Search Engines.

The only open-source and reliable project I know of which tries to solve all those extremely difficult problems mentioned has proven to be jQuery Ajaxy. It's effectively an extension to the jQuery History project mentioned before, providing a nice elegant high level interface to add AJAX functionality to the mix to take care of those difficult problems behind the scenes so we don't have to worry about them. It's also the chosen solution used in the last few commercial sites mentioned earlier.

Good luck, and if you have any further questions then just post a comment on this answer and I'll get to it asap :-)

balupton
Hey! Thanks very much for your answer, I know that my demo isn't made with AJAX, however I will use AJAX to make my own, but that demo demonstrates the effect what I want to achieve, your example: `http://wbhomes.com.au/#/home` is extremely cool, this is 100% how I wanted, without `?` and such things, but for me any version is good what works, however if you could show me how did you made that, I would be very very happy :). And I know that it's extremely difficult because no one posted(I didn't find) anything about it, and I don't really know how to make it, I'm not a pro in javascript.
CIRK
Thanks mate and I'm glad I've helped. Yeah I completely agree the wbhomes site is extremely cool! I've revised my post to go into the solution used for it (jQuery Ajaxy), so that should clear up anything left unsaid :-) If you want to know anything more then definitely feel free to post a comment, or you can always contact me directly on my website at www.balupton.com
balupton
Hi @balupton ! Ajaxy is nice and cool but I think there is a huge problem with it. I can't specify where I want to put the `content`. So for example I have `link1 - onclick calls page1.php` and `link2 - onclick calls page2.php` but I want `link1` to change `div content1` and `link2` to change `div content2`, I hope you understand what I'm talking about :) I think with this feature would be almost perfect ;)
CIRK
And something else, for example I have a `search` I write in it `balupton` then submit, then ajaxy changes the content but the URL is not changeing.
CIRK
And something else, if you could make it in plain Javascript too would be awesome! I think if you could make these, Ajaxy would be one of the most useful and powerful tools for developers who want to build Ajax powered apps :)
CIRK
Hey @Cirk. Good points and definitely somethings which I've been considering too. Having it coded in vanilla JS and use adapters for the frameworks is on the todo list. Current priority is releasing the CMS that powers balupton.com and documenting how to do some really advanced/neat stuff with Ajaxy. Regarding your points, would you be able to raise them on the Ajaxy support site here http://getsatisfaction.com/balupton/products/balupton_jquery_ajaxy as that way I'll be better equipped to deal with the issues :-) It's quite late here, so I'm off to bed. But very glad to keep this convo going!
balupton
Thanks for your fast reply @baluton ! I'm happy to hear that you want to make it! I'm really happy and I really appreciate your hard work! Good Night!
CIRK
+1  A: 

I think you can do that very easily using the onHashChange event present in HTML5 or using a JavaScript library that emulates that "hash" behavior in browsers that doesn't have full HTML 5 support. One such library might be MooTools onhashchange, but there are many others too.

Than if you have a HTML 5 aware browser, or such library that emulates the behavior just use:

window.sethash("#newsection");
to change to something new from javascript, and/or a callback to that onHashChange event to intercept it, depending on your use case scenarios.

Adrian A.
Indeed, using onhashchage is how most are doing it - including gmail.
A. Ionescu
The problem is that onhashchage is not natively supported by a lot of browsers, or they have quirks. The libraries provided add support for legacy browsers, plus this is just for hooking into the hash, not so much how the AJAX paradigms work.
balupton
+1  A: 

CorMVC Jquery Framework is done in that way, it is opensource you can dig into source and get the logic from it.

And actually it is pretty straight forward. The creator tells it nicely on this video below.

http://www.bennadel.com/resources/jing/2009-12-21_0933.swf

PS sorry can't post second link bc i'm a new user.

KakambaWeb
A: 

This is something that eludes most new AJAXian developers. It is though a rather simple issue to solve.

first thing you will need is the the jQuery core which is free at jquery.com

next you will need the jQuery hash change even plugin by Ben Alman which you can find here: http://benalman.com/projects/jquery-hashchange-plugin/ You won't need this for newer versions of browsers that support the html5 hashchange event but you will for older versions of browsers. you don't have to do anything but include this script in your page, it handles the rest.

now for your links you will need to construct them in a query string fashion like so:

<a href="user.php?q=/topic/article" class="dynlnk">Link Text/Image</a>

now you have links that go to pages and can be handled in php in case javascript is turned off. all you have to do is use the super global $_GET and parse the query string to handle page content.

now in your javascript on the page you will need make your links trigger hashchange. You can do that by replacing the ?q= with a # like this.

$(".dynlnk").each(function(){
    $(this).attr("href", $(this).attr("href").replace("?q=", "#"));
});

now your links will trigger the hashchange, the only thing left to do is bind the hashchange to a function that does something. This can be done very simply with jQuery like this:

$(window).bind( 'hashchange', function(e){

    //this splits the part after the hash so you can handle the parts individually.
    //to handle them as one just use location.hash
    pageparts = location.hash.split("/");

});

Now just add what ever code you do to handle your ajax and content.

now you just need one last bit of javascript to trigger the hashchange in case the page was loaded with a hash to begin with so you just call the windows trigger function when the page loads

$(window).trigger( 'hashchange' );

Hopefully this is clear enough, if not, don't hesitate to contact me to ask more questions.

Kelly Copley
A: 

Using hash links allows for bookmarkable/sharable links to trigger JavaScript code, instead of reloading the page. Ben Almans jQuery hashchange event allows you to bind an event handler to the hashchange event, this plugin works with older browsers that don't support this normally. An event handler bound to hashchange can read the hash part of the url, and call any function.

// register event handler
function bindHashchange() {

    $(window).bind('hashchange', function(event) {
        event.preventDefault();
        var label = location.hash.substring(1);
        handleLabel(label);
    });

    // trigger event so handler will be run when page is opened first time
    // otherwise handler will only run when clicking on hash links
    $(window).trigger('hashchange');
}

// read and handle hash part of url
function handleLabel(label) {

    if ( label.length > 0 ) {
        // using label from url
        switchPage(label);
    } else {
        // use the default label, if no hash link was present
        switchPage('start');
    }
}

// in this case, load hidden <div>'s into a <div id="content">
function switchPage(label) {
    if ( label == 'start ) {
        $('div#content').html($('div#start'));
    } else if ( label == 'some_other_page' ) {
        // do something else
    }
}

This other event handler can process 2 arguments separated by a dot ('.') in the same url.

function processHash() {

    var str = location.hash.substring(1);
    var pos = $.inArray('.', str);

    var label = '';
    var arg = '';

    if ( pos > -1 ) {
        label = str.substring(0, pos);
    } else {
        label = str.substring(0);
    }

    if ( pos > 1 ) {
        arg = str.substring(pos+1);
    }

    if ( label.length == 0 ) {
        // the default page to open of label is empty
        loadContent('start');
    } else {
        // load page, and pass an argument
        loadContent(label, arg);
    }
}

If regular expressions are used, any combination of characters can be parsed.

var registry = {};

// split on character '.'
var args = label.split(/\./g);

for ( i in args ) {
    var arg = args[i];

    // split on character '='
    var temp = arg.split('=');
    var name = temp[0];
    var value = temp[1];

    // store argument in registry
    registry[name] = value;
}
// registry is loaded, ready to run application that depends on arguments

This will transform the url:

mysite/#company.page=items.color=red

Into the following JavaScript Object:

Object { company=undefined, page="items", color="red"}

Then it is only a matter of running jQuery's show() or hide() functions on your selected elements.

This could be transformed into non-jQuery JavaScript, but then you would lose the functionality that Ben Alman delivers, which is crucial for a portable solution.

thnee
A: 

What you want is a way to support history in AJAX which can be done using many already existing libraries. I would recommend reading YUI 3 page on history.

Ashish