Tom Elliott
Tom Elliott

Reputation: 1926

Model instance replaced with remote method result in Angular call to Loopback

I have a Loopback API with an Angular front end, and have been seeing some strange behavior when trying to call a non-static remote method.

I've boiled it down to this example. When making a call like this:

$scope.myInstance = MyModel.findOne({}, function success(value){
  $scope.greeting = value.$prototype$hello({}, function success(){});
});

I'm finding that $scope.myInstance ends up containing the result of the call to $prototype$hello and $scope.greeting is empty. MyModel is defined with a remote call like this:

module.exports = function(MyModel) {

   MyModel.prototype.hello = function(cb) {
     cb(null,"Hello: " + this.name);
   }

   MyModel.remoteMethod(
     'hello',
     {
       isStatic: false,
       http: { verb: 'get' },
       returns: {arg: 'message', type: 'string'}
     }
   );

};

So if I have this in my template:

Greeting = {{ greeting }}, Instance = {{ myInstance }}

I see:

Greeting = {}, Instance = {"message":"Hello: Test","$promise":{},"$resolved":true}

With the greeting result clearly in place of the model instance. I would expect to see the model instance in the Instance variable:

Greeting = {}, Instance = Instance = {"name":"Test","id":1,"$promise":{},"$resolved":true}

There is a brief flash of the model during loading.

I can work around this by retrieving additional throwaway instances of the model, but I'm hoping someone knows why this is happening and if there's a cleaner solution.

UPDATE 08/12/2015: I've created a Plunker to demonstrate this problem here, but this only contains the client-side JS. For the full loopback project, I've added the code to a GitHub repo

Interestingly enough, the behavior is slightly different under Safari, which doesn't render the instance at all:

Greeting = {}, Instance =

The originally described behavior was seen under Chrome.

Upvotes: 0

Views: 839

Answers (1)

Labib Ismaiel
Labib Ismaiel

Reputation: 1340

I checked your plunker, and I think I got the issue here, your code is:

$scope.myInstance = MyModel.findOne({}, function success(value){
  $scope.greeting = value.$prototype$hello({}, function success(){});
});

let's forget about the success function for a second, findone() function returns your requested document from a mongodb, as I think, which means, naturally, the returned document or query will be stored in $scope.myInstance, which is how your app is behaving. Now for the success function, it's trying to call value.$prototype$hello which doesn't exist in the response object (value), so the value is undefined and that gets stored in the $scope.greeting that's why it is displaying as empty.

why $prototype$hello is undefined is simple, it's a prototype object if it was a part of your app but you are trying to access this function through a response object that doesn't have it.

I hope this answers your question

EDIT:

the problem is with this line

 $scope.greeting = value.$prototype$hello({}, function success(){});

just make like this:

value.$prototype$hello({}, function success(val){$scope.greeting = val.message;},function error(err){console.log(err);});

Edit 2

change your code to be like this:

ModelA.findOne({}, function success(value){
  //debugger;
  value.$prototype$hello({}, function success(val){$scope.greeting = val.message;},function error(err){console.log(err);});
}).$promise.then(function(res) {
  $scope.myInstance = res;
});

this way, you will not have bogus data in your variable before the promise is resolved. And, it's purely normal for the response object to have $promise, and $resolved attributes, because it's a resource promise object

EDIT 3

now after you clarified the issue on your last comment, I was able to understand it, I was looking for something else, but anyway they are related. what was happening is a conflict, you are doing two async calls, you should treat them that way, this is how the code should be:

ModelA.findOne({}).$promise.then(function(value) {
  $scope.myInstance = value;
  var v2 = angular.copy(value);
  v2.$prototype$hello({},
    function (val){
      $scope.greeting = val.message;
    },
    function (err){console.log(err);}
  );
});

let me know if you need more input regarding the code

Upvotes: 1

Related Questions