Ajax design patterns

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Ajax design patterns

Post by matthijs »

Haven't seen any discussion here about this, but think it would be interesting to hear and discuss about people's approach to "ajaxifying" their web apps. Ajax is of course quite a broad subject, but what I mean is:

- you build a web app on top of some MVC framework (your own or something like ZF)
- the web app has different kinds of content which can be posted using ajax. Say comments in a comment thread, posts in a forum, etc
- you might even combine several forms with different actions

I guess the Facebook page is a good example. Everything you want to do can be done from one place, starting with a single text field. Once it has focus you get a few icons in view, which all lead to more functionality like uploading images or videos, etc

Questions I would have:
How do you handle the ajax forms?
Do you have a non-js fallback with normal forms?
Do you develop two separate actions or controllers handling the normal and the ajax part?
How do you handle validation in the forms, do you reuse the validation which already exists in the models?

As an example of one approach, I just found out that ZF has something like contextswitch
http://framework.zend.com/manual/en/zen ... jaxcontext
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Re: Ajax design patterns

Post by alex.barylski »

Good question.

My own framework offers complete rendered sections of a web page automagically when you use a view manager class. For things like updating <select> lists I would have a separate JSON controller, personally, but thats me.

For things like adding the a comment to an existing list (ie: wordpress blog) is the most interesting question. Returning a raw data result like in JSON, would require rendering on the client into the required HTML, which is likley duplicated on the server already via a template.

I suppose I would make the comments an individual template and return that in AJAX requests but I'd rather return the comment just added. So I would probably just embed the single comment template into another template which render a list of results.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Ajax design patterns

Post by Eran »

Having a non-JS fallback is dependent on the specific site and form. When relevant, I often start with a non-JS solution and add the AJAX component on top of it - reusing the fields, form action, etc.

For form response that add content to the site, I usually have the smallest item (such as a comment) as a renderable view partial server-side, and use in according to context - render a comment list with it or return it from the server on successful creation of a new comment. As Alex said, having the rendering logic both on the server and in client is duplicate code that is hard to maintain.

It's worth noting that returning individual items via an AJAX operation would sometimes require binding new events to it (any JS functionality that already exists in the view on similar items). For that I often abstract the event binding operation and make restrict it to specific DOM contexts (jQuery makes this really easy).
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: Ajax design patterns

Post by matthijs »

@PCSpectra & pytrin: indeed it seems like there are 2 approaches in the example of posting something to an existing list.

1) add the new content through ajax and at the same time dynamically add it to the page. This would mean duplicating the "rendering logic". With that you probably mean the HTML that's needed to wrap around the new comment/post/item
2) add the new content by posting with Ajax and have an existing controller/action return the partial HTML complete with the new content

So that second option seems the best. How do those controllers and actions look like? Do you have separate controllers for handling the ajax part, separate actions or a switch inside existing actions to detect ajax calls?
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Ajax design patterns

Post by josh »

Yeah when the markup is duplicated I either

1) use a helper from within my javascript class and rename the file to .js.php ( so the markup looks 'hard coded' to the client who hits view source, but on the server it is dynamically generated )
2) ill output a template to a div and use javascript to fill in dynamic data from a json object and copy the resultant string into the body of the page
3) ill have a URL or route I can hit that will return fully rendered html that just fits in place on the page

Rather then using the context switch sometimes I just go

if( $this->isXhttpRequest() )
{ // do whatever }
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Ajax design patterns

Post by Eran »

I sometimes use separate actions for the AJAX requests, and sometimes reuse the same action action with switches on the type (like Josh suggested). All depending on how different the regular action is from the AJAX one.
User avatar
inghamn
Forum Contributor
Posts: 174
Joined: Mon Apr 16, 2007 10:33 am
Location: Bloomington, IN, USA

Re: Ajax design patterns

Post by inghamn »

I use context switching in my stuff, and it's been working quite well. (Not with ZF, but my own templating class). When every controller has the ability to give you HTML, XML, JSON, TXT, or whatever, you can save time and just write stuff once.

If some javascript needs data, you have a much easier time of figuring out where to get it. And usually don't have to write up a custom service for it.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: Ajax design patterns

Post by matthijs »

Interesting to hear some approaches. Could some of you post small snippets of code to show what you mean? Even if it's just one action or something which shows the basics. It might make it easier for me to visualize what you mean
User avatar
inghamn
Forum Contributor
Posts: 174
Joined: Mon Apr 16, 2007 10:33 am
Location: Bloomington, IN, USA

Re: Ajax design patterns

Post by inghamn »

In the addressing application I've been working on recently..here's the controller for searching for streets.
It looks for streets based on the name you send ($_GET['streetName']), and returns results in HTML, or whatever other format you ask it.

For the record, I use PageControllers. This controller lives at /BASE_URL/streets

Code: Select all

 
$template = isset($_GET['format']) ? new Template('default',$_GET['format']) : new Template();
 
if ($template->outputFormat == 'html') {
    $template->blocks[] = new Block('streets/breadcrumbs.inc');
    $template->blocks[] = new Block('streets/findStreetForm.inc');
}
 
if (isset($_GET['streetName'])) {
    $fields = AddressList::parseAddress($_GET['streetName'],'streetNameOnly');
    if (count($fields)) {
        $streets = new StreetList($fields);
    }
    else {
        $streets = new StreetList();
        $streets->find();
    }
}
elseif ($template->outputFormat != 'html') {
    $streets = new StreetList();
    $streets->find();
}
 
if (isset($streets)) {
    $template->blocks[] = new Block('streets/streetList.inc',array('streetList'=>$streets));
}
 
echo $template->render();
 
User avatar
inghamn
Forum Contributor
Posts: 174
Joined: Mon Apr 16, 2007 10:33 am
Location: Bloomington, IN, USA

Re: Ajax design patterns

Post by inghamn »

Now, for the AJAXy stuff....

The findStreetForm is a block (what most everyone else calls a partial) that I can include into any template that needs it. You see it called for up in that controller, if the user's getting HTML output.

I've become a huge fan of YUI. So, the findStreetForm does autocomplete by doing it's own searches against the very same URL, only it's asking for JSON.

Code: Select all

 
<div id="findStreetForm" class="yui-skin-sam">
    <form method="get" action="<?php echo $_SERVER['SCRIPT_NAME']; ?>">
        <fieldset><legend>Search</legend>
            <label for="streetName">Street Name</label>
            <div id="findStreetForm-autocomplete" style="width:15em;">
                <input name="streetName" id="streetName"
                        value="<?php echo isset($_GET['streetName']) ? View::escape($_GET['streetName']) : ''; ?>" />
                <div id="container"></div>
            </div>
            <button type="submit" class="search">Search</button>
        </fieldset>
    </form>
 
</div>
 
<script type="text/javascript">
findStreetForm_autosuggest = function() {
    var streetService = new YAHOO.util.XHRDataSource("<?php echo BASE_URL; ?>/streets");
    streetService.responseType = YAHOO.util.XHRDataSource.TYPE_JSON;
    streetService.responseSchema = {
        resultsList: "streets",
        fields: ["name"]
    };
    streetService.maxCacheEntries = 5;
 
    var findStreetFormAC = new YAHOO.widget.AutoComplete("streetName",
                                                        "container",
                                                        streetService);
    findStreetFormAC.generateRequest = function(query) {
        return '?format=json;streetName=' + query;
    }
 
    return{
        streetService: streetService,
        findStreetFormAC: findStreetFormAC
    };
}();
</script>
 
User avatar
inghamn
Forum Contributor
Posts: 174
Joined: Mon Apr 16, 2007 10:33 am
Location: Bloomington, IN, USA

Re: Ajax design patterns

Post by inghamn »

I organize my application's files like so:

Code: Select all

 
/application
    /classes
    /blocks
        /html
            /streets
                findStreetForm.inc
                streetList.inc
        /json
            /streets
                streetList.inc
        /xml
            /streets
                streetList.inc
        /txt
    /html
        /streets
            home.php
    /library
    /templates
        /html
            default.inc
            two-column.inc
            three-column.inc
            full-width.inc
        /json
            default.inc
        /xml
            default.inc
        /txt
            default.inc
 
So now, all that's left is to write up the streetList.inc block. And need to write a different version of that block for each output format I want to support.
So the JSON streetList.inc is:

Code: Select all

 
$streets = array();
foreach ($this->streetList as $street) {
    $name = addslashes($street->getStreetName());
    $town = addslashes($street->getTown()->getDescription());
    $notes = addslashes($street->getNotes());
    $string = <<<EOD
    {
        "id":"{$street->getId()}",
        "name":"$name",
        "town":"$town",
        "status":"{$street->getStatus_code()}"
    }
EOD;
    $streets[] = $string;
}
$streets = implode(",\n",$streets);
echo '{"streets":['.$streets.']}';
 
And the HTML streetList.inc is

Code: Select all

 
if (count($this->streetList)) {
    echo "
    <table>
        <thead>
            <tr>
                <th>Street Name</th>
                <th>Status</th>
                <th>Town</th>
            </tr>
        </thead>
        <tbody>
    ";
        foreach ($this->streetList as $street) {
            $name = View::escape($street->getStreetName());
            $status = View::escape($street->getStatus()->getDescription());
            $town = View::escape($street->getTown()->getDescription());
            echo "
            <tr>
                <td><a href=\"{$street->getURL()}\">$name</a></td>
                <td>$status</td>
                <td>$town</td>
            </tr>
            ";
        }
    echo "
        </tbody>
    </table>
    ";
}
 
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Ajax design patterns

Post by josh »

matthijs wrote: Could some of you post small snippets of code to show what you mean? Even if it's just one action or something which shows the basics. It might make it easier for me to visualize what you mean
This is a helper method that saves models, with data populate from a form. I use it in my controllers. If it is called from a form it sets a flash messenger (Zend parlance) and redirects with an http status code, if it is posted to from an ajax enabled form it sends some relevant stuff back via json

Code: Select all

 
/**
    * Method called after model saving takes place.
    * 
    * Method expects a form and a model, it takes data from form, populates data to model.
    * It finds model's mapper, and saves model
    * 
    * if the editing is taking place as part of an ajax call, basic information about the edited model is returned via json w/ a status code
    * otherwise for non-ajax calls, the doEdit() template method will be called
    * 
    * @param K12_Form
    * @param K12_Model
    */
    protected function save( $form, $model )
    {
        $isNewModel = $model->getId() == 0; // if model has no id, isNewModel = true
        $this->populateTo( $form, $model );
        $this->doSave( $form, $model );
        if( $this->_request->isXmlHttpRequest() )
        {
            $data = new stdClass();
            $data->status = 0;
            $data->mode = $isNewModel ? 'new' : 'edit';
            $data->model = new stdClass();
            $data->model->id = $model->getId();
            $data->model->title = (string)$model;
            return $this->_helper->json( $data );
        }
        return $this->saveSuccess( $model->getId() );
    }
I could have used a context switch but it would not have been apparent what data is actually relevant to what types of request, from looking at the controller method alone. Plus I would have duplicated viewscripts in each module then. And redirecting from a view script would also be a code smell!
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Ajax design patterns

Post by VladSun »

PCSpectra wrote:Returning a raw data result like in JSON, would require rendering on the client into the required HTML, which is likley duplicated on the server already via a template.
Well, I can't agree with this :)
My web-apps are fully AJAX featured. That is, except for the main page HTML View I have no more HTML code. Indeed, I don't have any server side Views - everything is sent to the user as JSON data (if you consider an JSON formatter helper a View ... I have one View ;) ). That is, the View part is always client side - no templates, no code duplication (except for the validation, which I think can't be done in other way).

Just today, I've read a short article about MVC and AJAX - http://wiki.apidesign.org/wiki/MVC
To MVP Again
Obviously, people tend to repeat the same thing again and again, just with new technologies. Thus with the rise of Ajax, where the GUI is represented inside a browser we are again closer to MVP as the user deals with the view elements directly.
So, we have MVP here ;)
There are 10 types of people in this world, those who understand binary and those who don't
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Re: Ajax design patterns

Post by alex.barylski »

My web-apps are fully AJAX featured. That is, except for the main page HTML View I have no more HTML code. Indeed, I don't have any server side Views - everything is sent to the user as JSON data (if you consider an JSON formatter helper a View ... I have one View ). That is, the View part is always client side - no templates, no code duplication (except for the validation, which I think can't be done in other way).
So what happens when someone visits your site on a mobile device like a blackberry, which might not have JS enabled by default? If templates rendered via client side (using XSLT, or whatever) chances are a mobile will not render anything but simple HTML.

No to mention SEF/SEO. Unless your pages are purely XML data structures which are rendered into HTML (but I recall JSON being the term) how does that affect SE's???

Cheers,
Alex
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Ajax design patterns

Post by Christopher »

VladSun wrote:My web-apps are fully AJAX featured. That is, except for the main page HTML View I have no more HTML code. Indeed, I don't have any server side Views - everything is sent to the user as JSON data (if you consider an JSON formatter helper a View ... I have one View ;) ). That is, the View part is always client side - no templates, no code duplication (except for the validation, which I think can't be done in other way).
So you have one piece of Javascript code that you load with the main page and that builds the page from JSON data for every page in your site?
(#10850)
Post Reply