[Catalyst] sane AJAX strategy

Bill Moseley moseley at hank.org
Mon Jan 8 19:31:43 GMT 2007


On Mon, Jan 08, 2007 at 04:04:14PM +0100, Daniel McBrearty wrote:
> I am talking here though about scenarios where it's more "AHAH" than
> "AJAX" ... the function that makes the request just sticks it as-is
> into the page, rather than doing some kind of decode on it. Mostly
> because that seems simpler, and I like simple ...

Right, I use AJAX to mean both.

> ok ... so does the the controller know that the req is ajax? how? an
> added argument like "?ajax=true" perhaps ... ?

I look at the request headers.

=cut

sub is_ajax {
    my $c = shift;

    my $headers = $c->req->headers;

    return $headers->header('x-prototype-version')
        || ( ($headers->header('x-requested-with')||'') eq 'XMLHttpRequest' );
}

> right. so in this case there is a generic " [% IF ajax %] " in your
> template code that suppresses headers, footers and so on?

Kind of.  Something like this -- I capture the tables into
page.just_table and then:

    SWITCH page.type || template.type;

        CASE 'text';  # render as-is.  Page is not html
            content;

        CASE 'html';
            content WRAPPER page/html.html
                          + page/layout.html        # standard site layout
                          + includes/tabs.html      # include tabs, if available
                          + includes/pager.html;    # also page navigation

        CASE 'ajax_table';  # just return the content of the table
            page.just_table;

    END;

> >For AJAX requests that don't update the entire page content, like an
> >auto-complete search box, I still use the same controller as for the
> >non-ajax request but then the controller has a little extra code to
> >return just the search results not the entire new content -- it's just
> >one extra line of code in most cases.  Not always the most efficient
> >method (since I end up returning more columns than is really needed for
> >the ajax update), but so far has not been an problem.
> >
> 
> so do you typically use the same controller action, and have a flag to
> tell it to act differently?

Yes, kind of.  Some things are common enough (like search boxes) so I
have a method for it.

So a controller that shows a list of users (possibly limited by a
search) looks like this:

sub list : Path {
    my ($self, $c, $limit ) = @_;

    my $options = $self->search_options( $c, $limit );

    return if $c->ajax_search( $options, qw/ first_name last_name email / );


    $c->paged_list( $options  );
}

search_options parses out the parameters from the request -- $option
is basically:

    $options->{class}->search( $options->{criteria} )

kind of thing.  Then ajax_search() does the query and uses a template
to format for the auto-complete javascript.  paged_list() is just a
method to generate a list based on rows and columns and how it should
be sorted.

Not very helpful without seeing all the code, I suppose, but it's just
stuff I use in a bunch of controllers so it's factored out. 




-- 
Bill Moseley
moseley at hank.org




More information about the Catalyst mailing list