1

I'm still new to sails.js and currently trying to get returned object from different action.

What currently I know is if I use 'getUserTransaction' action inside 'UserController', then I can only return it to 'getUserTransaction.ejs' view using locals (_.each). (CMIIW) example:

//UserController
getUserTransaction: function (req, res, next){
   UserTransaction.find({user:req.param('userid')}).exec(function foundTransactions(err, transactions){
      if(err) return next(err);

      if(!transactions) return next();

      res.view({
         transactions: transactions
      });
   });
}

//getUserTransaction.ejs 
...
<% _.each(transactions, function(transaction){ %>
   <tr>
       <td><%= transaction.data %></td>
       <td><a href="<%= transaction.path %>">Link</a></td>
   </tr>
<% }); %>
...

But, what if I want to return object from 'getUserHobby' action indside 'UserController' to 'getUserTransaction.ejs' view?. this is my code and I can't get it right

//UserController
getUserHobby: function (req, res, next){
   UserHobby.find({user:req.param('userid')}).exec(function foundHobbies(err, hobbies){
      if(err) return next(err);

      if(!hobbies) return next();

      res.view('user/getUserTransaction', {
         hobbies: hobbies
      });
   });
}

//getUserTransaction.ejs
...
<% _.each(hobbies, function(hobby){ %>
   <tr>
       <td><%= hobby.type %></td>
       <td><%= hobby.name %></td>
   </tr>
<% }); %>
...

And I've tried to do it and returned 'hobbies undefined'. So how I should get it right.

Regards

j.elmer
  • 1,441
  • 2
  • 17
  • 36
  • Is your `getUserTransaction.ejs` file located in the `views/user/` folder? – Yann Bertrand Aug 03 '15 at 09:51
  • yes, `getUserTransaction.ejs` is located in the `views/user/` folder – j.elmer Aug 03 '15 at 13:01
  • I'm not sure to understand your question. Please clarify it (is the first part about what you know useless? "And I've tried to do it and returned 'hobbies undefined'"?) – Yann Bertrand Aug 05 '15 at 09:20
  • It is not useless. The first time I try it, hobbies return undefined. After I tried your solution, it solved the 'undefined' problem but still list of hobbies is not shown to `getUserTransactions.ejs`. The list of hobbies is shown only to `getUserHobby.ejs` because the views file name is the same with the action named `getUserHobby` in UserController. What I asked is how to get data from action that named `getUserHobby` to `getUserTransaction.ejs` ? – j.elmer Aug 05 '15 at 09:37
  • I'm sorry but I still don't understand what you want to achieve. Do you want to display the `transactions` and `hobbies` lists in the same view? – Yann Bertrand Aug 05 '15 at 09:43
  • Yes.. I want to display list of transactions and hobbies in the same view through different action. Sorry for bad description. – j.elmer Aug 05 '15 at 09:45
  • I think I've understood now, I've edited my answer below – Yann Bertrand Aug 05 '15 at 11:51
  • Hi @Yann Bertrand. Actually, I already know those answer since the beginning. But, what I want to ask is it possible to display list of transactions and hobbies using different(separated) actions? Get data from `getUserTransactions` action and from `getUserHobby` action, and then send it to `getUserTransactions.ejs` view. Because I want to do real-time table pagination to Transactions and Hobbies within the same view. Because we need callbacks to the actions for `.paginate()` right? If there is no other answer, what you said is the correct answer. What do you think? Thanks for your patience. – j.elmer Aug 06 '15 at 01:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/85274/discussion-between-yann-bertrand-and-john-elmer-jo-el). – Yann Bertrand Aug 06 '15 at 07:27

1 Answers1

0

First of, in a Sails controller action, you shouldn't use the 3rd param (next).

Unlike Express middleware methods, Sails controller actions should always be the last stop in the request chain--that is, they should always result in either a response or an error. While it is possible to use next in an action method, you are strongly encouraged to use policies instead wherever possible.

You should use the built in response methods even if you want to throw an error.

Here is how I would write my controller action:

// Inside api/controllers/UserController.js
getUserTransactions: function (req, res) {
  if(!req.param('userid'))
    return res.badRequest(); // Send a 400 response back down to the client indicating that the request is invalid

  UserTransaction
    .find({ user: req.param('userid') })
    .exec(function foundTransactions(err, transactions){
      if(err)
        return res.negotiate(err); // Send an appropriate error response back down to the client

      // If there is no transactions, you can display a message in your view
      return res.ok({ transactions: transactions }); // Send a 200 ("OK") response back down to the client with the provided data
  });
}

And here is how you could write your corresponding view:

// Inside views/user/getUserTransaction.ejs
<% if(data.transactions.length) { %>
    <!-- display each transactions... -->
    ...
<% } else { %>
    <p>This user has no transaction yet.</p>
<% } %>

For your other action, here is how you can use res.ok with a pathToView param

res.ok({ hobbies: hobbies }, 'user/getUserTransactions');

Your view has to be located in the views/user/getUserTransactions.ejs file in order to run correctly.


Now we've reviewed your code, we can answer your question.

So you want to call an controller's action in another one. This is possible but not recommended.

Here is what you should do:

// api/controllers/UserController.js
// In your getUserTransactions method (you should change its name)
// Get the user transactions
UserTransaction
  .find({ user: req.param('userid') })
  .exec(function foundTransactions(err, transactions) {
    if(err) return res.negotiate(err);

    // Get the user hobbies
    UserHobby
      .find({ user: req.param('userid') })
      .exec(function foundHobbies(err, hobbies) {
        if(err) return res.negotiate(err);

        return res.ok({
          transactions: transactions,
          hobbies: hobbies
        });
   });
});

You can also use services to simplify your controllers.

// api/services/UserService.js
module.exports.getUserTransactions = function (userId, cb) {
  UserTransaction
    .find({ user: userId })
    .exec(cb);
};

module.exports.getUserHobbies = function (userId, cb) {
  UserHobby
    .find({ user: userId })
    .exec(cb);
};

// Inside api/controllers/UserController.js
UserService
  .getUserTransactions(req.param('userid'), function (err, transactions) {
    if(err) return res.negotiate(err);

    UserService
      .getUserHobbies(req.param('userid'), function (err, hobbies) {
        if(err) return res.negotiate(err);

        return res.ok({
          transactions: transactions,
          hobbies: hobbies
        });
    });
});
Community
  • 1
  • 1
Yann Bertrand
  • 3,084
  • 1
  • 22
  • 38
  • Thank you for your response and correction. I'm still new to sails.js, so I'm gonna try on it. – j.elmer Aug 03 '15 at 14:19
  • Hi @Yann Bertrand, I tried to do it like you. But there is a problem if I use `res.ok`. It become transactions is undefined, even I already put `res.ok({transactions: transactions}, 'user/getUserTransaction')` and already use the routing point. But if I use `res.view`. It just returned normally. Even without routing point. Regards – j.elmer Aug 04 '15 at 04:42
  • I think you have to use `data.transactions` instead of `transactions` in your views. I'll edit my answer if it works. – Yann Bertrand Aug 04 '15 at 07:44
  • Hi @Yann Bertrand, after I use `data.transactions` in my views, the data returned to views. But only if action name is the same with the views filename. In this case `getUserTransactions` as action name and `getUserTransactions.ejs` as views filename. But if views filename is different, in this case `getUserHobby.ejs` can't get the returned data. Regards – j.elmer Aug 05 '15 at 02:55
  • I don't get what you mean by "can't get the returned data". Do you have something in that `data`? Please log `err` and `hobbies` in your controller's action. – Yann Bertrand Aug 05 '15 at 08:32
  • Sorry, I think I use wrong words on comment before. What I mean is, the data that returned from `getUserHobby` through `data.hobbies` is not empty in `getUserHobby.ejs`. But, returned empty in `getUserTransactions.ejs` – j.elmer Aug 05 '15 at 08:53
  • So `data.transactions` is `undefined` in `getUserTransactions.ejs`? – Yann Bertrand Aug 05 '15 at 09:07
  • No, `data.transactions` and `data.hobbies` is already defined. The problem is, I want to put `data.hobbies` in `getUserTransactions.ejs` but returned empty data. If I put `data.hobbies` in `getUserHobby.ejs` returned data. – j.elmer Aug 05 '15 at 09:11