如何在不使用指令的情况下从angular.js中的其他控制器更新视图?

时间:2016-07-12 22:00:53

标签: angularjs

我有一个角度应用程序,页面上有2个部分。

1部分是侧栏,给出了一个概要。让我们说:

Players 5 // {{ numOfPlayers }}

代码是一个ajax调用。我不想增加,因为这个号码可以通过另一个呼叫增加。我需要在获取数组长度后运行ajax调用。

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

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

现在位于主页面上的完全独立的控制器中。用户可以添加播放器。我如何拥有它以便我可以更新导航控制器?

angular.module('app').controller('mainController', function($scope,$http) {
    $http.post(.....).then(function(data) {
    //update the numOfPlayers so the nav is updated.
    });
});

8 个答案:

答案 0 :(得分:5)

使用服务

您可以使用服务来保存共享数据和$watch更改:



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>
&#13;
&#13;
&#13;

使用父控制器

您可以使用父控制器(比如pageController)来保存共享数据:

&#13;
&#13;
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;
});
&#13;
<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>
&#13;
&#13;
&#13;

旁注:

两种方法:

  1. 最好将播放器阵列用作共享资源。在这个例子中,我试图保持简单。

  2. 最好更新mainController的初始资源值,而不是navController。在示例中,我尝试与您的代码保持一致。

答案 1 :(得分:4)

首先,我建议使用最佳实践并使用组件而不是ng-controller。

所以你有两个组成部分:

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

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

现在,您可以通过服务

在它们之间共享州数据
angular.module('app').service('PlayersService', function(){
  this.players = [];
  this.getAll() = () => {};
  this.add(player) = () => {};
});

只有一个棘手的部分是你需要观看所有组件玩家更改:

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)
   }
});

因此,在这两种情况下,范围属性 numOfPlayers 都会更新。

答案 2 :(得分:2)

由于您在一个页面上有两个部分,我的建议是使用一个或多个组件而不是单独的控制器。示例如下:

&#13;
&#13;
angular
  .module('exampleApp', [])
  .controller('ExampleController', ExampleController);

function ExampleController() {
  var vm = this;
  vm.numPlayers = 0;
}

angular
  .module('exampleApp')
  .component('playerSummary', {
    bindings: {
      numPlayers: '<'
    },
    template: `<p>{{ $ctrl.numPlayers }}</p>`
  });

angular
  .module('exampleApp')
  .component('playerAddition', {
    bindings: {
      numPlayers: '='
    },
    controller: function() {
      function addPlayer() {
        this.numPlayers++;
      }
      this.addPlayer = addPlayer;
    },
    template: `<button type="button" ng-click="$ctrl.addPlayer()">+</button>`
  });
&#13;
<!DOCTYPE html>
<html ng-app='exampleApp'>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
</head>

<body ng-controller="ExampleController as vm">
  <player-summary num-players="vm.numPlayers"></player-summary>
  <player-addition num-players="vm.numPlayers"></player-addition>
</body>

</html>
&#13;
&#13;
&#13;

不推荐,但您也可以使用$ rootScope或catch并发出事件。

您还可以绑定到服务属性,例如下面的示例,或直接绑定到服务。

&#13;
&#13;
angular
  .module('exampleApp', []);

angular
  .module('exampleApp')
  .controller('FirstController', FirstController);

function FirstController(PlayerService) {
  var vm = this;
  vm.players = PlayerService.players;
}
FirstController.$inject = ['PlayerService'];
angular
  .module('exampleApp')
  .controller('SecondController', SecondController);

function SecondController(PlayerService) {
  var vm = this;
  vm.addPlayer = function() {
    PlayerService.addPlayer();
  }
}
SecondController.$inject = ['PlayerService'];
angular
  .module('exampleApp')
  .service('PlayerService', PlayerService);

function PlayerService() {
  var PlayerService = this;
  PlayerService.players = [];

  PlayerService.addPlayer = function() {
    PlayerService.players.push({});
  }
}
&#13;
<!DOCTYPE html>
<html ng-app='exampleApp'>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
</head>

<body>
  <div ng-controller="FirstController as vm">
    <p>{{vm.players.length}}</p>
  </div>
  <div ng-controller="SecondController as vm">
    <button ng-click="vm.addPlayer()">+</button>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

正如Khalil Malki所说,您可以观看服务价值

正如Jaqen H&#39; ghar所提到的,你可以使用父控制器。

答案 3 :(得分:1)

您可以使用angular.factory()

执行此操作

angular.service(); or $localStorage and or $sessionStorage

首先进行全局调用,而不是在控制器内调用:

示例:

angular.factory('updateVal', function(){
    var data;
    return {
    getPlayers: function(){
     return $http.get('/players').success(function(results){
        data = results;
       return data;
     });
    },
   setPlayers: function(val){
     if(val){ 
      data = val;
      return data;         
      } 
      else {       
       return data;
      }
    }
   }  
});

在你的控制器中: 第一个控制器

angular.module('app').controller('nav', function($scope,updateVal){
 $scope.numOfPlayers = updateVal.getPlayers();

 $scope.$watch(function(){
    return updateVal.setPlayers().length > 0;
  }, function(){
    $scope.numOfPlayers = updateVal.setPlayers();
  })
})

第二控制器:

angular.module('app').controller('mainController',       function($scope,$http,updateVal) {
    // this function update the players updateVal.getPlayers();
    $http.post(.....).then(function(data) {
    //update the numOfPlayers so the nav is updated.
     // after posting call this function:
      updateVal.setPlayers(data);
    });
});

使用angular.service:

可以这样做:

angular.service('updatePlayers', function(){

var updatedPlayers;
this.setPlayers = function(args){

     updatedPlayers = args;
     } 
this.getPlayers = function(){
return updatedPlayers;
   }
 })

在您的第一个控制器中:

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

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

在第二个控制器中:

angular.module('app').controller('mainController', function($scope,$http,updatePlayers) {
    $http.post(.....).then(function(data) {
    //update the numOfPlayers so the nav is updated.
     updatePlayers.getPlayers();
    });
});

已修改以修复拼写错误

答案 4 :(得分:1)

更好的方法是两个有两个指令:

  1. 一个page指令
  2. 一个nav指令
  3. nav指令会将一些数据作为输入。在这种情况下,玩家的数量可以是输入之一。然后,当您将nav指令嵌套在page指令中时,您可以将数据从page传递到nav,而nav会自动更新价值变化:

    <强> HTML

    <page></page>
    

    <强>的JavaScript

    app.directive('page', function() {
      return {
        restrict: 'E',
        controller: function($scope, playerSvc) {
          playerSvc.getPlayers.then(function(resp) {
            $scope.players = resp.data;
          });
        },
        template: '<header> blah</header> <nav player-count="players.length"></nav> <footer></footer>'
      };
    });
    
    app.directive('nav', function() {
      return {
        restrict: 'E',
        scope: { playerCount: '=' },
        template: '<div> player count: {{playerCount}} </div>'
      };
    
    });
    

    通过这样做,您可以隔离指令(组件)并创建清晰的边界。每个组件或指令都有一个小的责任。在这种情况下,nav获取一些数据并显示它们,并且还负责导航。 page指令为页面上的不同组件或指令提供全局数据。您可以使用相同的想法并决定谁将玩家添加到玩家列表中。因为nav指令与players.length相关联,所以players更新后会自动更新。

答案 5 :(得分:1)

可能会调用nav控制器中的方法,以便范围变量更新,最终通过双向绑定更新视图

angular.module('app').controller('nav', function($scope,$http) {
 $rootScope.$on("CallMethodNavController", function(){
       $scope.navMethod();
    });
$scope.CallMethodNavController=function(){
$http.get('/players').then(function(data) {
 $scope.numOfPlayers = data.players.length;
}    
});
});

然后在第二个控制器中,一旦添加了一个玩家,你就会调用这个方法:

        $rootScope.$emit("CallMethodNavController", {});

答案 6 :(得分:1)

无需为此创建手表或活动。

使用服务在整个应用中获取,存储,更新和分享玩家阵列。

而不是创建长度的原始变量...存储对控制器和视图中数组的引用做{{players.length}}并让角度视图观察者负责更新。

angular.module('app').factory('playersService', function($http){
     // now have an array to share across app
     // and reference to addPlayer function
     var factory ={players:[], addPlayer: addPlayer };
     // load the players and add them to array
     $http.get('/players').then(function(response) {
         Array.prototype.push.apply(factory.players, response.data);
     });


     function addPlayer(player){
        return $http.post(url, player).then(function(resp){
           // add new player to shared array
           factor.push(resp.data);
        }
     }

    return factory;
});

导航控制器

angular.module('app').controller('nav', function($scope,playersService) {
     $scope.players = playersService.players; // store full array reference
});

导航视图

 Number Players: {{players.length}} <!-- angular will automatically watch and update --> 

其他控制器

angular.module('app').controller('mainController', function($scope,playersService) {

    $scope.newPlayer={};// bind to ng-model's in form
    $scope.saveNewPlayer = function(){
       playersService.addPlayer($scope.newPlayer).then(function(){
           alert('Number of players in nav will already be updted');
           // clear form
           $scope.newPlayer={};
       })
    });

}); 

答案 7 :(得分:1)

使用$ emit和$ on 从主cintroller      $ rootScope。$ broadcast(&#39; update&#39;,&#39; status&#39;){$ http.post(.....)。then(function(data){     //更新numOfPlayers以更新导航。     });}

and in your nav controller use
$scope.$on('eventName', function (event, args) { $http.get('/players').then(function(data) {
 $scope.numOfPlayers = data.players.length;});});

$ broadcast从父节点传送到子节点,因此父控制器中的任何更改都将反映在子控制器