Re: Handling ajax and non ajax requests in the same controller

671 views
Skip to first unread message

James Roper

unread,
Nov 27, 2012, 11:06:05 PM11/27/12
to play-fr...@googlegroups.com
Ok, so ajax means XMLHttpRequest, which is not used when doing jsonp.  If ajax is what you want, then assuming you were using a client library (like jQuery) that sets the X-Requested-With:XMLHttpRequest header, you could just have a function like

boolean isAjax() {
 
return "XMLHttpRequest".equals(Http.Context.current().request().getHeader("X-Requested-With"));
}

and call this in each controller.  Then you don't need a separate path at all.

But since you aren't using ajax, you're using jsonp, you can't do this.  In which case, rather than all the overhead of defining every route twice with a separate path, I'd recommend just putting a jsonp parameter in the query string, and then you can:

boolean isJsonp() {
 
return "true".equals(Http.Context.current().request().getQueryString("jsonp"));
}

So now your action can just be:

@BodyParser.Of(BodyParser.Text.class)
public static Result channelIndex(Long channelId) {
   
if (isJsonp()) {
       
// return jsonp
   
} else {
       
// return html
   
}
}


On Wednesday, 28 November 2012 02:29:29 UTC+11, Abhi wrote:
Hello,

I would like to be able to differentiate an ajax request over a full page request from the browser. For that reason, I have setup my ajax code to request all resources over the /ajax/ suffix. So if I have example.com/channels/1234, when fetching the same page over ajax, I would request example.com/ajax/channels/1234. How would I go about doing this?

1. Setup routes for each endpoint - One normal and one for ajax and set a default parameter. like this:
GET    /channels/:channel                   controllers.Channels.channelIndex(channel: Long, isAjax="false")
GET    /ajax/channels/:channel              controllers.Channels.channelIndex(channel: Long, isAjax="true")

2. Have a base Controller that checks if the url starts with "/ajax/" and set an instance variable isAjax to True or False. Then the controller renders a complete HTML page if isAjax is false else render a JSONP.

I would prefer to go with 2 as that makes it more generic and maintainable than having lots of routes. Could someone point out as to how I could achieve this ?

My frontend interacts over a JsonPish interface, this is my sample controller code

    @BodyParser.Of(BodyParser.Text.class)
    public static Result channelIndex(Long channelId, String isAjax) {
      String content = channel.render(
                  Channel.findById(channelId)
                  ).body();

      ObjectNode result = Json.newObject();
      result.put("status", "OK");
      result.put("message", content);

      return ok("$$.foo(" + result + ")");

    }

PS: I come from a python background. I will need some guidance to get things started.

--
Abhi

Abhi Tubby

unread,
Nov 28, 2012, 12:11:17 AM11/28/12
to play-fr...@googlegroups.com
James,

Thanks for those tips. What I meant was a JSONPish like interface not
pure JSONP. Essentially, I needed a way to figure out if the call to
the end point is a full page request or via an ajax and accordingly
only serve updates.

--
Abhi
> --
>
>

James Roper

unread,
Nov 28, 2012, 12:55:03 AM11/28/12
to play-fr...@googlegroups.com
Well, if you're using AJAX, just go with the X-Requested-With header option, it's much simpler than anything else.

Alexandre Stanislawski

unread,
Nov 28, 2012, 2:50:38 AM11/28/12
to play-fr...@googlegroups.com
Why do you need to even know that your client (be it a browser, a web app or something else) is doing to fetch your resources??

XHR calls are basically just http requests, so you'd better do mime type checking, if necessary, in order to know the format of the data you need to give back. (and there are helpers in play to do that). What is your play version?

@james : X-headers are no more best practices... http://tools.ietf.org/html/rfc6648


--
 
 



--
Alexandre Stanislawski
@bobylito
suaviter in modo, fortiter in re

Julien Richard-Foy

unread,
Nov 28, 2012, 3:13:55 AM11/28/12
to play-fr...@googlegroups.com
You can also look at the Accept request header to determine if it’s an
Ajax request or not (provided you won’t set it to "text/html").

Abhi

unread,
Nov 28, 2012, 12:36:31 PM11/28/12
to play-fr...@googlegroups.com, Alexandre Stanislawski
On 28-11-2012 13:20, Alexandre Stanislawski wrote:
> Why do you need to even know that your client (be it a browser, a web
> app or something else) is doing to fetch your resources??
>
I am implementing the 3rd party API over a different set of end points.
Instead of serving JSON data, I am serving fragments of HTML depending
on whether the request was a landing(User directly goes to the URL) or
when he navigates from another part of my webapp.
> XHR calls are basically just http requests, so you'd better do mime
> type checking, if necessary, in order to know the format of the data
> you need to give back. (and there are helpers in play to do that).
> What is your play version?
>
Which is why I wanted my ajax calls over a separate over /ajax/. But,
then your suggestion of checking for the mime type is equally appealing.
I will take that into consideration. I am using Play 2.0.4 using Java.

> @james : X-headers are no more best practices...
> http://tools.ietf.org/html/rfc6648
>
>


--
Abhi

James Ward

unread,
Nov 28, 2012, 8:02:26 PM11/28/12
to play-fr...@googlegroups.com
You can do something like:

public static Result index() {
Http.Context.current().response().setHeader("Vary", "Accept");

if (Http.Context.current().request().accepts("text/html")) {
return ok(index.render());
}
else {
return ok(getSomeJson());
}
}

Just beware that Chrome is currently broken with this approach:
http://code.google.com/p/chromium/issues/detail?id=94369

It is broken when the user hits the back button and the last request to
a the URL they are going back to was JSON. In this case the user sees
JSON in their browser. Horrible breakage and spec noncompliance.
Luckily the Chrome team has fixed it. (After the community fought for a
long time with them.)

-James
Reply all
Reply to author
Forward
0 new messages