$ scope变量不在$ rootScope。$ on中更新

时间:2015-03-17 07:05:54

标签: javascript angularjs angular-ui-router

此展示号码1更改按钮。当我单击该按钮时,它应该触发$ state.go并在控制器内,它应该检测$rootScope.$on中的事件并将数字更新为2。但是,出于某种原因,即使使用$ digest或$ apply,我也无法更新数字(data.id)。

http://plnkr.co/edit/3qHnIm?p=preview

HTML

<!DOCTYPE html>
<html ng-app="myapp">

  <head>
        <script data-require="angular.js@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
    <script data-require="ui-router@*" data-semver="0.2.13" src="//rawgit.com/angular-ui/ui-router/0.2.13/release/angular-ui-router.js"></script>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title></title>
    <meta name="description" content="" />
    <meta name="viewport" content="width=device-width" />
  </head>

  <body class="container">
    <div ui-view=""></div>
    <div ng-controller="state2Ctrl">
      <a href="#" ng-click="change()">Change</a>
    </div>
    <script src="app.js"></script>
    <script src="controllers.js"></script>
  </body>

</html>

state1.html

<p>{{ data.id }}</p>

JS

var app = angular.module('myapp', ['ui.router']);

app.config(function($stateProvider, $urlRouterProvider) {

  $urlRouterProvider.otherwise('/state1/0');

  $stateProvider
    .state('state1', {
      url: '/state1/:id',
      controller: 'state1Ctrl',
      templateUrl: 'state1.html'
    });
});

app.controller('state2Ctrl', function ($scope, $rootScope, $state, $stateParams) {
  $scope.i = 1;

  $scope.change = function(){
    console.log('change state1');
    $state.go('state1', {id: $scope.i++});  
  };
});

app.controller('state1Ctrl', function ($scope, $rootScope, $state, $stateParams) {
  $scope.data = {id: 1};

  $rootScope.$on('$stateChangeSuccess', function(evt, toState, toParams, fromState, fromParams) {
    console.log($scope.data);

    $scope.$apply(function() {
      $scope.data = {id: 2};  
      console.log($scope.data);
    });
  });

});

有人可以找出我为什么data.id未在视图中获得更新的错误吗?

更新1

从下面的Radim响应中,我更改了代码以更好地反映我的真实代码:http://plnkr.co/edit/yyg0Hrl5IgzP4e44aRet?p=preview

基本我在我的情况下没有父州的情况。我想要做的是从SAME状态,用新的params触发该状态并更改一些$ scope变量对象。就是这样。

JS

var i = 1;

app.controller('state1Ctrl', function($scope, $rootScope, $state, $stateParams) {
  $scope.change = function() {
    console.log('change state1: ' + i);
    $state.go('state1', {
      id: i++
    });
  };

  $scope.data = {
    id: 1
  };

  $rootScope.$on('$stateChangeSuccess', function(evt, toState, toParams, fromState, fromParams) {
    console.log('$stateChangeSuccess: ');
    console.log($scope.data);

    $scope.data = $scope.data || {};
    $scope.data.id = toParams.id;
    console.log('After assign:');
    console.log($scope.data);

  });

});

点击更改4次后,我发现了$stateChangeSuccess事件的数量,如下面的屏幕截图所示。如果你能帮忙解释并避免这种情况,我不确定为什么。

enter image description here

1 个答案:

答案 0 :(得分:1)

原因是,您每次都在重新创建data

// this will create new reference to data
// in current scope, while not effecting any other (parent)
$scope.data = {id: 2}; 

如果您想更新现有参考,我们必须这样做

// here we work with existing reference
// if it was created, it will be used, the id property will be updated
$scope.data = $scope.data  || {}; 
$scope.data.id = 2;

an updated version

状态现在是父级,我们将继续继续使用$ scope,因此我们可以将其用作$scope.data的共享持有者

  $stateProvider
    .state('state1Parent', {
      template: '<div ui-view=""></div>',
      controller: 'state1ParentCtrl',
    });
  $stateProvider
    .state('state1', {
      parent: 'state1Parent',
      url: '/state1/:id',
      controller: 'state1Ctrl',
      templateUrl: 'state1.html'
    });

控制器更新了def:

app.controller('state1Ctrl', function ($scope, $rootScope, $state, $stateParams) {
  // no $scope.data definition, used the inherited
  //$scope.data = {id: 3}; 

  $rootScope.$on('$stateChangeSuccess', function(evt, toState, toParams, fromState, fromParams) {
    console.log($scope.data);

    // because this state change listener still have access to $scope
    // we can update the value of data.id
    // because it is in fact parent reference
    // se even next state will have access to it


    //$scope.$apply(function() {
      $scope.data = $scope.data || {};  
      $scope.data.id = toParams.id;  
      console.log($scope.data);
    //});
  });

});

父控制器,带参考数据定义

app.controller('state1ParentCtrl', function ($scope, $rootScope, $state, $stateParams) {
  $scope.data = { id : 1 };
})

检查here

我不是说这是我们应该去的方式。但试图说明问题是什么,以及如何解决问题

EXTEND:如果没有父母州,我们可以这样做吗?

来自扩展问题:

  

基本我没有在我的情况下具有状态的情况。我想要做的是从 SAME状态,触发状态与新参数并更改一些 $ scope 变量对象。就是这样。

那么,这里有什么问题。

1)controller生命周期是角度世界中最短的。它只会在州内生活。一旦我们离开它,导航到其他 - 它将消失(如果没有内存泄漏挂钩)

2)一旦控制器被销毁,控制器的范围将被销毁......

3)我们必须将国家视为孤立的岛屿。如果我们确实可以访问状态$scope - 即使在内部声明$rootScope.$on('$stateChangeSuccess'中 - 我们也可以访问当前控制器的当前状态的$范围。事实上,我们为内存泄漏

创建了一个候选者
app.controller('state1Ctrl', ...
  ...
  $rootScope.$on('$stateChangeSuccess', ...
     // HERE - $scope belongs to Controller, and its life cycle is very short
     $scope.data =

4)如果我们想要改变某些值,那么“SAME state” - 转换后我们必须将其移出OUT。它不能处于当前状态,因为当前状态/视图/控制器(及其范围)将不相同。

5)如何保存数据的方式是 - 服务(单例)或父模型(将通过视图/范围继承继承)

6)$rootScope.$on应该在某个.run()方法中声明 - 在控制器之外。但在这种情况下,它似乎没有增加任何价值。因为如果我们将共享数据放入某个服务......我们可以做任何事情,例如,在其他控制器中也是如此