John Steed John Steed - 2 months ago 7
AngularJS Question

Call To Service Function: Not Populating Scope On First Execution

I am refactoring some angularjs code to make the controller leaner and move some logic into a service.

Old Code This works OK.

In Controller...

var firmSearchRequest = {
type : "ByDate",
startDate : $scope.startDate,
endDate : $scope.endDate
};

firmService.getFirms(firmSearchRequest).then(function(response) {
firmService.appendFirmList(response.data);
$scope.firmList = firmService.getFirmList();
});


In Service...

var firmList = [];

this.getFirms = function(firmSearchRequest) {
return httpService.putForResponse('firms/search', firmSearchRequest);
};


this.appendFirmList = function(newfirmList){
firmList = firmList.concat(newfirmList);
}


this.getFirmList = function() {
return firmList;
};


Refactored Code Does not work as expected

In Controller...

var firmSearchRequest = {
type : "ByDate",
startDate : $scope.startDate,
endDate : $scope.endDate
};

$scope.firmList = firmService.appendFirmListByDate(firmSearchRequest);


In Service...

var firmList = [];

this.appendFirmListByDate = function(firmSearchRequest){

this.getFirms(firmSearchRequest).then(function(response) {
firmList = firmList.concat(response.data);
});

return firmList;

};

this.getFirms = function(firmSearchRequest) {
return httpService.putForResponse('firms/search', firmSearchRequest);
};


Unexpected Behavior

For the refactored code, when I click the button that executes the code above, I receive no console error but the
$scope.firmList
is empty. When I click the button a second time for a second execution,
$scope.firmList
is correctly populated.

Why is the first execution not working correctly? What am I doing wrong?

Answer

In your controller

$scope.firmList = firmService.appendFirmListByDate(firmSearchRequest);

here the function firmService.appendFirmListByDate() is a simple function and will run synchronously so the value will be returned immediately so the returned value in this case is empty array named firmList

so the question arises why you get the correct list when you click the button for second time.

  • when you clicked the button for second time then the value inside the array var firmList = [] was inserted because of the promise that ran for the first time and it was

    this.getFirms(firmSearchRequest).then(function(response) {          
        firmList = firmList.concat(response.data);
    });
    
  • when you clicked the button second time then the function still ran synchronously and you got the value that was populated in first step.

Note- so every time you are getting a value that was populated by the promise in the last step.

Important point

  • you can't refactor your code in this way

  • making a thin controller doesn't mean removing the promise out of it. It means the the business logic should not be there. so your promises should be inside service which should return a promise to the controller and data manipulation etc. should done inside the service

Returning a promise from service

this.appendFirmListByDate = function(firmSearchRequest){
   return new Promise(function(resolve,reject){
        //if firmList contains data then just return it
        if(firmList.length!==0){
               resolve(firmList);
         }else{
            this.getFirms(firmSearchRequest).then(function(response) {          
               firmList = firmList.concat(response.data);
               resolve(firmList);
            }).catch(function(error){
                  reject(error);
            });
        }

    });
};