Didier Jean Charles
Didier Jean Charles

Reputation: 507

AngularJs and two Controllers

I am writing an application that is running AngularJs & Bootstrap on the frontend - and using angularjs' $http to make calls to an API...I have two controllers within one app -- the first controller displays the person's name and the second controller displays a list of performances that this person has seen...

<html lang="en" ng-app="myapp">
...
    <div class="panel-body" ng-controller="Ctrl">
        <div class="row">
            <div class="col-sm-3" style="height: 50px;">
                <div class="well well-sm">
                    First Name: 
                    <a href="#" editable-text="user.fname">{{ user.fname || "empty" }}</a>
                </div>
            </div>
            <div class="col-sm-3" style="height: 50px;">
                <div class="well well-sm">
                    Last Name: 
                    <a href="#" editable-text="user.lname">{{ user.lname || "empty" }}</a>
                </div>
            </div>
        </div>
    </div>
    <div class="list-group" ng-controller="Ctrl2">
        <div ng-repeat="obj in performances" >
            <div class="list-group-item">
                <h4 class="list-group-item-heading">
                <span class="badge">
                {{$index+1}}</span> {{ obj["Perf_name"] || "empty" }}</h4>
                <p class="list-group-item-text">
                        Date: {{ obj["Perf_dt"] || "empty" }}<br />
                        Theater: {{ obj["Theater"] || "empty" }}<br />
                </p>
            </div>
        </div>
    </div>
...
</html>

In the JS file I have the following code

Declare my variables and module

var app = angular.module("myapp", ["xeditable"]); 
var q = getUrlParameter("q"); // get the query param
var baseurl = "https://some.domain/service/getCRM";
var baseurl2 = "https://some.domain/service/getPerformances";

Create a service to be used by both controllers

app.service('crmService', function () {
    this.id = 0; 
    this.getID = function () { return this.id };
    this.setID = function (newid) { this.id = newid; };
});

Define Controller #1

app.controller('Ctrl', function ($scope, $http, crmService) {
    $http({
        method: 'GET',
        url: baseurl,
        respondType: 'json',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        params: {
            phone_no: q
        }
    }).then(function successCallback(response) {
        $scope.user = {
            fname: response.data[0]["FirstName"],
            lname: response.data[0]["LastName"]
    }
        crmService.setID(response.data[0]["CRM_ID"]);

        console.log("*** OUTPUT LINE 1: " + crmService.getID());

    }, function errorCallback(response) {
        console.log("**ERROR");
        console.log(response);
    });
});

Define Controller #2

app.controller('Ctrl2', function ($scope, $http, crmService) {
    console.log("*** OUTPUT LINE 2: " + crmService.getID());

    var promise = $http.get(baseurl2 + "?crm_id=" + crmService.getID());
    promise.then(
        function (response) {
            $scope.performances = response.data;
    });
});

Console output

*** OUTPUT LINE 2: 0
*** OUTPUT LINE 1: 123456

Questions:

  1. Why is the second controller outputting before the first, I assume it is because AngularJs by default executes its code asynchronously, and if that's the case, why did the "promise" not work?
  2. What I need to happen is, I make my GET call in the first controller block and assign the customer ID using my service...I then go on to the second controller block and using the customer ID, from my service (which was set within the first controller block) - get the customer's performances

So I have to first controller working fine, but the second controller keeps thinking that the customer ID is 0 - when it should be 123456

What am I missing?

FYI: when I hard code an ID for the second controller to use, I get actual performance records back - so I know everything will work once I figure out how to share values between my controllers

Upvotes: 0

Views: 139

Answers (1)

JB Nizet
JB Nizet

Reputation: 691625

Why is the second controller outputting before the first

Because the second controller logs the ID as soon as it's instanciated, whereas the first one logs it once it has received, asynchronously, a response to an HTTP request. The promise did work, since the output is logged in the console.

What I need to happen is, I make my GET call in the first controller block and assign the customer ID using my service...I then go on to the second controller block and using the customer ID, from my service

You're doing your job more complex than it should be: using a single controller would be much easier here, since the model of the second one depends on what the first one does.

You could broadcast an event from the first controller to signal that the ID has been set, and listen to the event in the second one to get the data at tis time.

app.controller('Ctrl', function ($scope, $http, $rootScope, crmService) {
    $http({
        ...
    }).then(function successCallback(response) {
        ...
        crmService.setID(response.data[0]["CRM_ID"]);
        console.log("*** OUTPUT LINE 1: " + crmService.getID());
        $rootScope.$broadcast('crmIdChanged');
    };
});

app.controller('Ctrl2', function ($scope, $http, crmService) {
    function getPerformances() {
        var id = crmService.getID();
        if (id != 0) {
            var promise = $http.get(baseurl2 + "?crm_id=" + crmService.getID());
            promise.then(
                function (response) {
                    $scope.performances = response.data;
            });
        }
    }

    getPerformances();
    $scope.$on('crmIdChanged', getPerformances);
});

You could even broadcast the even from the service itself.

Upvotes: 1

Related Questions