0

So I have been working on a SPA project using Sailsjs. The problem is:

When the first page loads, I use res.view or res.render in my controller. But, for subsequent requests, I dont want to use res.view or res.render, rather I'd like to use res.json.

Right now, I use the method:

return req.param('json') ? res.json(myObj) : res.view('layout', myObj);

This works, but I was looking for a more generic and abstract method in which my controller itself would know (on the basis of req.param('json')) whether to use res.view or res.json without me having to tell it explicitly.

Any help ?

myusuf
  • 11,810
  • 11
  • 35
  • 50

2 Answers2

2

This is what res.ok() is for.

In the controller action below, res.ok will either display the myAction.ejs using data as the view locals, or respond with data as JSON, depending on how the request came in (i.e. via AJAX, sockets or a regular browser request):

module.exports = {

    myAction: function(req, res) {

       var data = {someKey: "someVal"};

       return res.ok(data);

    }

}

Internally, the ok response uses req.wantsJSON to determine what to do; it checks headers, looks for an xhr object and generally does its best to guess your intent. req.wantsJSON is available for all requests (as is req.isSocket), so you can use them yourself as needed.

sgress454
  • 24,870
  • 4
  • 74
  • 92
  • 1
    Thanks for the answer. I read up on res.ok [here](https://github.com/balderdashy/sails/blob/master/lib/hooks/responses/defaults/ok.js). Since I am making an SPA app that will render the first page from server, I will always have to provide the 'layout.ejs' argument, since any page can be the first page. Also, my json requests will either come through AJAX or socket. Will `req.wantsJSON` behave reliably ? – myusuf Sep 06 '14 at 14:18
  • You shouldn't have to specify a layout unless you're using a layout template other than **views/layout.ejs**. As for `wantsJSON`, yes, it will return `true` in both those situations. You can check the code for it [here](https://github.com/balderdashy/sails/blob/f8870e796c22f5f9e39fb9d7c0047d73c82b157e/lib/hooks/request/qualifiers.js) – sgress454 Sep 08 '14 at 06:33
  • I have found that, if I do not provide a layout, then it does not take **views/layout.ejs** by default. Rather, it takes the view in the controller folder, by the name of the action. So, if I'm in UserController and profile action, then by default sails renders **user/profile.ejs**. – myusuf Sep 09 '14 at 09:39
  • You're confusing layouts with views. Rendering **user/profile.ejs** is exactly what `res.view` (which `res.ok` calls) is supposed to do. The *layout* is a separate **.ejs** file which you can use as a template to wrap *around* your view--the specific view will be inserted at the `<%- body %>` tag in the layout file. See the [default Sails **layout.ejs** file](https://github.com/balderdashy/sails-generate-views/blob/master/templates/layout.ejs) for reference--it contains the ``, `` and `` tags, so that your views don't have to. – sgress454 Sep 10 '14 at 02:03
0

So after a bit of tinkering, I resolved this using a service.

I wrote a service (in GlobalUtils.js):

render: function (req, res, obj) {
    if(req.param('json')) {
        return res.json(obj);
    }
    else {
        return res.view('layout', obj);
    }
}

And I use this service in my controllers, like so:

return GlobalUtils.render(req, res, myObj);

But still, looking for a better method.

myusuf
  • 11,810
  • 11
  • 35
  • 50