1

I am trying to learn AngularJS and i am making a test app. I have a table that gets populated with data returned from a WebService (list of publishers) via $http.get().

When the user clicks a row (publisher) i want to fill a second table with the list of employees of the selected publisher. By using the F12 tools (Network+Console) i see that the data is returned but the second table is not filled/updated.

html

<!DOCTYPE html>
<html ng-app="myApp">
<head lang="en">
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/style.css" type="text/css" />
    <script src=""></script>
    <script src="js/angular.js"></script>
    <script src="js/scripts.js"></script>
    <script src="js/app.js"></script>
    <title>My SPA</title>
</head>
<body>

    <header>
        <h1 id="page-title">Header</h1>
        <nav>
            <ul>
                <a href="#"> <li>Menu 1</li> </a>
                <a href="#"> <li>Menu 2</li> </a>
                <a href="#"> <li>Menu 3</li> </a>
                <a href="#"> <li>Menu 4</li> </a>
            </ul>
        </nav>
    </header>

    <div ng-controller='PublishersController' class="table-wrapper">
        <table class="data-table" />
        <thead>
            <tr>
                <th ng-repeat="(key,val) in publishers[0]">{{key}}</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat='pub in publishers' ng-click='getPublishersEmployees(pub.pub_id)'>
                <td ng-repeat='(key,val) in pub'>{{val}}</td>
            </tr>
        </tbody>
        </table>
    </div>

    <div ng-controller='PublishersController' class="table-wrapper">
        <table class="data-table" />
        <thead>
            <tr>
                <th ng-repeat="(key,val) in employees[0]">{{key}}</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat='employee in employees'>
                <td ng-repeat='(key,val) in employee'>{{val}}</td>
            </tr>
        </tbody>
        </table>
    </div>

</body>
</html>

JS

var urlBase = "http://localhost:2041";

var app = angular.module('myApp', []);

app.factory('myFactory', ['$http', function ($http) {

    var webAPI = '/api/query';
    var webService = urlBase + webAPI;
    var myFactory = {};

    myFactory.getCategories = function () {
        return $http.get(webService + '/getCategories');
    };
    myFactory.getCategorySalesByMonth = function (id) {
        return $http.get(webService + '/getCategorySalesByMonth/' + id);
    };

    myFactory.getPublishers = function () {
        return $http.get(webService + '/getPublishers');
    };
    myFactory.getPublishersEmployees = function (id) {
        return $http.get(webService + '/getPublishersEmployees/' + id);
    };

    return myFactory;
}]);

app.controller('PublishersController', ['$scope', 'myFactory', 
    function ($scope, myFactory) {

    $scope.status;
    $scope.publishers;
    $scope.employees;

    getPublishers();

    function getPublishers() {
        myFactory.getPublishers()
            .success(function (publishers) {
                $scope.publishers = publishers;
            })
            .error(function (error) {
                $scope.status = 'Unable to load publishers data: ' + error.message;
            });
    }

    $scope.getPublishersEmployees = function (id) {
        myFactory.getPublishersEmployees(id)
            .success(function (employees) {
                $scope.employees = employees;
        console.log($scope.employees);
            })
            .error(function (error) {
                $scope.status = 'Error retrieving employees! ' + error.message;
            });
    };
}]);

What am i doing wrong?

Christos Baziotis
  • 5,845
  • 16
  • 59
  • 80
  • Your template causes two separate controllers, each with its own scope, to be instantiated. You modify the scope of the first controller, but that won't change anything to the scope of the second one. – JB Nizet May 09 '14 at 14:27
  • I use the same controller (PublishersController) in both divs. I edited my post. – Christos Baziotis May 09 '14 at 14:28
  • 2
    Both controllers have the same type, but there are two different instances of the same controller type. And each instance has its own scope. Controllers are not singletons. Each time you have ng-controller="...", a new scope is created, and a new controller is instantiated. – JB Nizet May 09 '14 at 14:30

1 Answers1

3

The problem is you use separate controllers for PublishersController and EmployeesController. Angular will create separate scopes for your controllers. Therefore, when you assign $scope.employees = employees in your PublishersController, it does not reflect on the scope created by EmployeesController

Try:

<div ng-controller='PublishersController' class="table-wrapper">
        <table class="data-table" />
        <thead>
            <tr>
                <th ng-repeat="(key,val) in publishers[0]">{{key}}</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat='pub in publishers' ng-click='getPublishersEmployees(pub.pub_id)'>
                <td ng-repeat='(key,val) in pub'>{{val}}</td>
            </tr>
        </tbody>
        </table>

        <table class="data-table" />
        <thead>
            <tr>
                <th ng-repeat="(key,val) in employees[0]">{{key}}</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat='employee in employees'>
                <td ng-repeat='(key,val) in employee'>{{val}}</td>
            </tr>
        </tbody>
        </table>
  </div>

That solution above is just to point out your problem. I don't know your application design, you may not follow this solution but restructure your code to best fit your application design (like storing the employees in a shared service,...).

Here I propose another solution but I'm not sure if it fits with your application. You just use your original HTML code with PublishersController and EmployeesController. In your PublishersController, your could broadcast an event from rootScope:

.success(function (employees) {
             $rootScope.$broadcast("employeeLoaded",employees);
       })

Don't forget to inject $rootScope to your PublishersController:

app.controller('PublishersController', ['$scope', 'myFactory','$rootScope', 
    function ($scope, myFactory,$rootScope)

In your EmployeesController, you could subscribe to this event:

$scope.$on("employeeLoaded",function (event,employees){
     $scope.employees = employees;
});

For more information about event in angular, check out Working with $scope.$emit and $scope.$on

Community
  • 1
  • 1
Khanh TO
  • 48,509
  • 13
  • 99
  • 115