Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I update the view from a different controller in angular.js without using directive?

Tags:

angularjs

I have an angular app that has 2 sections on the page.

1 section is the sidebar which gives a synopsis. Let's say it says:

Players 5 // {{ numOfPlayers }}

The code is an ajax call. I do not want to increment as this number could be increased by another call. I NEED to run the ajax call after to get the array length.

angular.module('app').controller('nav', function($scope,$http) {

  $http.get('/players').then(function(data) {
     $scope.numOfPlayers = data.players.length;
  });
});

Now in a completely seperate controller that is on the main page. A user can add a player. How do I have it so I can update the nav controller?

angular.module('app').controller('mainController', function($scope,$http) {
    $http.post(.....).then(function(data) {
    //update the numOfPlayers so the nav is updated.
    });
});
like image 909
KingKongFrog Avatar asked Jul 12 '16 22:07

KingKongFrog


2 Answers

Use a Service

You can use a service to hold the shared data and $watch changes:

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

app.service("playersService", function () {
    this.numOfPlayers = 0;
});

app.controller("navController", function ($scope, $http, playersService) {
    // Update the shared resource initial value with GET result
    // $http.get('/players').then(function(data) {
    //     playersService.numOfPlayers = response.data.length;
    // });
    playersService.numOfPlayers = 0;

    $scope.$watch(function () { return playersService.numOfPlayers; }, function (value) {
        $scope.numOfPlayers = value;
    });
});

app.controller("mainController", function ($scope, playersService) {
    $scope.addPlayer = function () {
        // POST and update the shared resource with result
        // $http.post(.....).then(function(data) {
        playersService.numOfPlayers++;
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="TestApp">
    <section ng-controller="navController">
        <h1>Nav</h1>
        Players {{ numOfPlayers  }}
    </section>
    <section ng-controller="mainController">
        <h1>Main</h1>
        <button ng-click="addPlayer()">
            Add player
        </button>
    </section>
</div>

Use Parent Controller

You can use a parent controller (say pageController) to hold the shared data:

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

app.controller("pageController", function ($scope) {
    $scope.numOfPlayers = null;
});

app.controller("mainController", function ($scope, $http) {
    $scope.addPlayer = function () {
        // POST and update the shared resource with result
        // $http.post(.....).then(function(data) {
        $scope.$parent.numOfPlayers++;
    };
});

app.controller("navController", function ($scope, $http) {
    // Update the shared resource initial value with GET result
    // $http.get('/players').then(function(data) {
    //     $scope.$parent.numOfPlayers = response.data.length;
    // });
    $scope.$parent.numOfPlayers = 0;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="TestApp" ng-controller="pageController">
   <section ng-controller="navController">
      <h1>Nav</h1>
      Players {{ numOfPlayers  }}
   </section>
   <section ng-controller="mainController">
      <h1>Main</h1>
      <button ng-click="addPlayer()">
         Add player
      </button>
   </section>
</div>

Side Notes:

In both approaches:

  1. Might be better to use players array as a shared resource. In the example I tried to keep it simple.

  2. Might be better to update the initial resource value from mainController and not the navController. In the example I tried to be consistent with your code.

like image 145
Jaqen H'ghar Avatar answered Nov 15 '22 08:11

Jaqen H'ghar


First of all I would suggest to use best practices and use component instead of ng-controller.

So you have 2 components:

angular.module('app').component('nav', {});

and

angular.module('app').component('main', {});

Now you can share state data between them via services:

angular.module('app').service('PlayersService', function(){
  this.players = [];
  this.getAll() = () => {};
  this.add(player) = () => {};
});

Only one tricky part is that you need to watch in all your components for players change:

angular.module('app').component('nav', {
   controller: function($scope, PlayersService){

     PlayersService.getAll();
     $scope.$watch(() => PlayersService.players.length, (playersLength) => this.numOfPlayers = playersLength)
   }

});


angular.module('app').component('main', {
     controller: function($scope, PlayersService){

     //PlayersService.add(player);
     $scope.$watch(() => PlayersService.players.length, (playersLength) => this.numOfPlayers = playersLength)
   }
});

So in both cases scope property numOfPlayers gets updated.

like image 23
Stepan Suvorov Avatar answered Nov 15 '22 08:11

Stepan Suvorov