1

I am trying to do the following thing:

I have a model, say myModel which has some method calculateSomething. I defined that function by writing something like this in the MyModel.js file:

MyModel.prototype.calculateSomething = function(cb){
    ...
    return cb(null,result)
} 

Now I want to include the result of calculateSomething in the json whenever an instance of MyModel is returned from the api.

How do I do this? I tried using the "loaded" hook, but I believe this hook gets executed before the MyModel instance is created, so I can't call the calculateSomehing method there.

EDIT: It turns out that I can just use the "loaded" hook. I can use the ctx.instance in the hook to get the object.

I was confused by the documentation : "LoopBack invokes this hook after the connector fetches data, but before creating a model instance from that data". Is the documentation wrong or am I misunderstanding it?

Ward Beullens
  • 393
  • 5
  • 18

1 Answers1

1

How about using Remote Hooks (on mymodel.js):

// run before any static method eg. MyModel.find
MyModel.beforeRemote('*', function(ctx, myModel, next) {
  myModel.calculateSomething(function(err, something) {
    if (err) throw err

    myModel.something = something
    next()
  })
});

OR

If you need to do it on object initialization phase (while operation hook loaded seems to be not working) maybe you can try the model hook afterInitialize assuming no async call invoked from calculateSomething:

MyModel.afterInitialize = function() {
    this.something = this.calculateSomething(function(err, result) {
        return result
    })
}

OR

As discussed below, if you need do async call and/or want to have this logic on subclasses, I think you should consider implementing createSomething not as object/prototype method but as a mixins. I haven't tried this personally though but it looks quite suitable to your need.

Yohanes Gultom
  • 3,782
  • 2
  • 25
  • 38
  • Thanks for your answer! I have not tested this, but I expect this to fail when i do a request like GET api/relatedmodel/id/mymodels ? In that case i would want to get a list of myModel objects each with a something field. – Ward Beullens Aug 20 '16 at 16:52
  • I don't think it would work if the myModel is included in the json of a related model either? – Ward Beullens Aug 20 '16 at 16:53
  • Ah, I tested it and it is exacly what I was asking for. Thanks! I will accept your answer. But i immediately have a follow up question: In my case myModel is a class that is extended by a bunch of subclasses. I noticed that myModel.afterInitalize is not called if one of the subclasses is initialized. Is there a better way than to write an afterInitialize function for each of the subclasses? – Ward Beullens Aug 20 '16 at 17:14
  • Oops, it turns out that it is not exacly what i was asking for because the afterInitialize function is synchronous, so i can't call calculateSomething there? – Ward Beullens Aug 20 '16 at 17:19
  • Why can't you do that? I tried this code and it worked: MyModel.afterInitialize = function() { this.something = this.calculateSomething(function(err, result) { return result }) } As for subclasses, I haven't got any experience but you may want to take a look at mixins https://docs.strongloop.com/display/public/LB/Defining+mixins – Yohanes Gultom Aug 20 '16 at 17:55
  • It is not asynchronous, so loopback does not wait for the result of calculateSomething. In your case the calculateSomething is probably just a function that returns a value directly. So it might work, but in my case the calculateSomething has to query the database, it does not finish before the api has responded to the request, therefore the result is not included. – Ward Beullens Aug 20 '16 at 18:27
  • I see, you are right. Async function is not working in afterInitialize. I think the best solution that I can think of is implementing `calculateSomething` not as model's method but as a mixins – Yohanes Gultom Aug 21 '16 at 02:30
  • Sorry for my late response. I don't see how you would do this using mixins? – Ward Beullens Aug 23 '16 at 15:17
  • I'd implement `calculateSomething` inside `loaded` hook of a mixins and attached it to every models just like shown in https://stackoverflow.com/questions/25438663/dynamic-properties-or-aggregate-functions-in-loopback-models/32285839#32285839 – Yohanes Gultom Aug 25 '16 at 09:42