Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I´v got a "detail" view and a controller that initilizes data with an id.

My view:

<div ng-app="AFApp" ng-controller="AgentCtrl" ng-init="init('@Model.Id')">

My controller:

$scope.id;
$scope.agent = {};

$scope.init = function (id) {
    $scope.id = id;
    getAgent();
    getAgentStatus();
    getSystemInfo();
    getActions();
};

The problem is that the method "getAgentStatus();" gets executed before "getAgent();". The "getAgentStatus" needs the $scope.agent data that "getAgent" provides. The function getAgentStatus has an attached timer, and it gets the value as the timer elepses but not in the init function. Can someone please help me out with the method execution sequence in angular controllers and how the id parameter is provided the best possible way.

See methods below:

function getAgent() {
        agentDataFactory.getAgent($scope.id)
            .success(function (data) {
                $scope.agent = data;
            })
            .error(function (error) {
                console.log('Unable to load data: ' + error.message);
            });
    };

function getAgentStatus() {

        if (typeof ($scope.agent.ServiceUrl) == 'undefined' || $scope.agent.ServiceUrl == null) {
           console.log('getAgentStatus: ServiceUrl is undefined ' + JSON.stringify($scope.agent));
        }

        agentDataFactory.getAgentStatus($scope.agent.ServiceUrl)
            .success(function (data) {
                $scope.agent.CurrentStatus = data.Status;
                $scope.agent.CurrentInterval = data.Interval;
            })
            .error(function (error) {
                console.log('Unable to load data: ' + error);
            });

        $timeout(getAgentStatus, 3000);
    };
share|improve this question
1  
Why can't you call getAgentStatus() inside the success handler for getAgent()? –  callmekatootie Jan 14 at 20:46
    
Thanks for your reply, that works as well. As I mentioned below. I am still curious of the reason for the method sequence behavior in the controller. –  Claes-Philip Staiger Jan 15 at 9:22
1  
I am not sure if this related to asp.net, but by the looks of it, getAgent() is an asynchronous call that resolves a promise. Since it is asynchronous, it does get executed before getAgentStatus(), but after making the asynchronous call, getAgenStatus() is called immediately. –  callmekatootie Jan 15 at 9:27

1 Answer 1

up vote 1 down vote accepted

You can pass getAgentStatus() as a callback parameter to getAgent() and have it executed in the success callback (at which point agent will be defined):

function getAgent(callback) {
    agentDataFactory.getAgent($scope.id)
        .success(function (data) {
            $scope.agent = data;
            callback && callback();
        })
        .error(function (error) {
            console.log('Unable to load data: ' + error.message);
        });
};

$scope.init = function (id) {
    $scope.id = id;
    getAgent(getAgentStatus);
    getSystemInfo();
    getActions();
};

Short explanation:

Some highlights first:

  • agentDataFactory.getAgent($scope.id).success(...).error(...);:
    Creates a promise (which will be resolved) asynchronously and registers two callbacks, one if the promise is successfully resolved and one for the case of an error.

  • .success(function (data) { $scope.agent = data; }):
    Registers a callbackfor when the promise is successfully resolved. When (and if) that happens, $scope.agent will be set.

  • function getAgentStatus() { if (typeof ($scope.agent.ServiceUrl...: Tries to access some properties of $scope.agent and thus requires the object to be defined.

So, what happens with your code:

  1. getAgent() is gets called.
    [$scope.agent is undefined]
  2. A promise is created that when resolved will set $scope.agent.
    [$scope.agent is undefined]
  3. getAgent() returns and getAgentStatus() is called.
    [$scope.agent is undefined]
  4. getAgentStatus() tries to access $scope.agent's properties and fails.
    [$scope.agent is undefined]
  5. The promise created in step 2 is resolved and its success callback get executed.
    [$scope.agent is finally defined]

My version of the code ensures that getAgentStatus() is not executed before the promise is resolved and thus $scope.agent is defined:

  1. getAgent() is gets called.
    [$scope.agent is undefined]
  2. A promise is created that when resolved will set $scope.agent.
    [$scope.agent is undefined]
  3. getAgent() returns and other functions get called (e.g. getSystemInfo(), getActions(), etc.).
    [$scope.agent is undefined]
  4. The promise created in step 2 is resolved and its success callback get executed.
    [$scope.agent is finally defined]
  5. Only now does getAgentStatus() get called and it works as expected since...
    [$scope.agent is defined]

Take a look at the $q service for more info on Angular promises.

share|improve this answer
    
Thanks very much, that actually did the trick in this particular situation. I will use that solution. I am however curious of the reaso for the method sequence behavior in the controller. Thanks again! –  Claes-Philip Staiger Jan 15 at 7:48
    
@Claes-PhilipStaiger: I added some explanation of what is going on in each case. Please, do let me know if it doesn't make sense :) –  ExpertSystem Jan 15 at 11:26
    
Thanks for explanation, it make sense. I will look in to the promise of the repository. I can call the getAgentStatus() when the promise is resolved. Is it recommended to add promises to the controller functions as well? –  Claes-Philip Staiger Jan 15 at 13:20
    
I don't really understand what you mean by your last question. In any case, promises are a good thing that make asynchronous stuff easier to handle and interact with. So, promises won't hurt anyone - at the very worst they might be unnecessary. (BTW, if this answer helped you with your problem, please consider accepting/upvoting it.) –  ExpertSystem Jan 15 at 13:26
1  
If you are fetching data (which is by definition an async operation) you can't avoid using promises. If your question is whether you should have your "promising" methods in the controller, the truth is that Angular Services are a better fit for such "utility" methods. You can accept an answer by checking the little checkmark on the left next to the answer. There are also two arrow-buttons (up for upvoting, down for downvoting). –  ExpertSystem Jan 15 at 15:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.