更改指令中的控制器范围变量不会反映在控制器功能中 [英] changing a controller scope variable in a directive is not reflected in controller function

查看:26
本文介绍了更改指令中的控制器范围变量不会反映在控制器功能中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的指令中,我有一个控制器变量,当您按下指令中的按钮时,页面会增加.但是,调用控制器函数的下一行 scope.alertPage() 并未反映此更改.注意,当你点击按钮时页面仍然提示为 1!

我知道我可以通过在控制器中添加 $scope.$apply 来解决这个问题,但随后我收到错误消息,指出摘要已经发生.

Plunker

app = angular.module('app', []);app.controller('myCtrl', function($scope) {$scope.page = 1;$scope.alertPage = function() {警报($scope.page);}})app.directive('增量器', function() {返回 {范围: {页面:'=',警报页面:'&'},模板:'<button ng-click="incrementPage()">增量页面</button>',链接:功能(范围,元素,属性){scope.incrementPage = function() {scope.page += 1;范围.alertPage();}}}})

html 模板:

 页面是{{page}}<incrementer page='page' alert-page='alertPage()'></incrementer>

解决方案

之所以没有立即显示更新后的值是因为2路绑定只更新了父级(或指令的消费者作用域)作用域的绑定值在消化周期中.触发 ng-click 后会发生摘要循环.因此控制器中的 $scope.page 尚未更新.您可以通过使用 timeout 以多种方式解决此问题,这将推迟在摘要循环结束时运行的操作.您也可以通过设置一个将值保存为 2 路绑定属性的对象来实现.由于 2 向绑定属性和父作用域共享相同的对象引用,因此您将立即看到更改.

方法 1 - 使用超时:

 scope.incrementPage = function() {scope.page += 1;$timeout(scope.alertPage)}

方法 2 - 绑定对象:

//在你的控制器中$scope.page2 = {value:1};//在你的指令中scope.incrementPage = function() {scope.page.value += 1;范围.alertPage();}

方法 3 - 使用带参数的函数绑定传递值:

//在你的控制器中$scope.alertPage = function(val) {警报(val);}

<div incrementer page="page" alert-page="alertPage(page)"></div>

//在指令中scope.incrementPage = function() {scope.page += 1;scope.alertPage({page:scope.page});}

app = angular.module('app', []);app.controller('myCtrl', function($scope) {$scope.page = 1;$scope.page2 = {value:1};$scope.alertPage = function() {警报($scope.page);}$scope.alertPage2 = function() {警报($scope.page2.value);}})app.directive('incrementer', function($timeout) {返回 {范围: {页面:'=',alertPage: '&',第2页:=",alertPage2: '&'},模板:'<button ng-click="incrementPage()">增量页面</button>',链接:功能(范围,元素,属性){scope.incrementPage = function() {scope.page += 1;scope.page2.value += 1;$timeout(function(){ scope.alertPage() });范围.alertPage2();}}}})

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script><div ng-app="app" ng-controller="myCtrl"><div incrementer page="page" alert-page="alertPage()" page2="page2" alert-page2="alertPage2()"></div>

In my directive, I have a controller variable, page which gets incremented when you press the button in the directive. However, the next line, scope.alertPage() which calls the controller function does not reflect this change. Notice, when you click the button page is still alerted as 1!

I know I can fix this by adding $scope.$apply in the controller but then I get the error that says a digest is already taking place.

Plunker

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

app.controller('myCtrl', function($scope) {

  $scope.page = 1;

  $scope.alertPage = function() {
    alert($scope.page);
  }

})

app.directive('incrementer', function() {
  return {
    scope: {
      page: '=',
      alertPage: '&'
    },
    template: '<button ng-click="incrementPage()">increment page</button>',

    link: function(scope, elem, attrs) {
      scope.incrementPage = function() {
          scope.page += 1;
          scope.alertPage();
      }
    }
  }
})

html template:

  <body ng-app='app' ng-controller='myCtrl'>
    page is {{page}}

    <incrementer page='page' alert-page='alertPage()'></incrementer>
  </body>

解决方案

The reason why it does not show the updated value immediately is because the 2 way binding updates the parent (or the consumer scope of the directive) scope's bound value only during the digest cycle. Digest cycle happens after the ng-click is triggered. And hence $scope.page in the controller is not yet updated. You can get around this in many ways by using a timeout which will defer the action to run at the end of the digest cycle. You could also do it by setting an object which holds the value as 2-way bound property. Since 2-way bound property and parent scope share the same object reference you will see the change immediately.

Method 1 - using a timeout:

  scope.incrementPage = function() {
     scope.page += 1;
     $timeout(scope.alertPage)
  }  

Method 2 - Bind an object:

 //In your controller
 $scope.page2 = {value:1};

//In your directive 
scope.incrementPage = function() {
     scope.page.value += 1;
     scope.alertPage();
 }  

Method3 - Pass the value using function binding with argument:

//In your controller
$scope.alertPage = function(val) {
  alert(val);
}

and

<!--In the view-->
<div incrementer page="page" alert-page="alertPage(page)"></div>

and

//In the directive
scope.incrementPage = function() {
     scope.page += 1;
     scope.alertPage({page:scope.page});
 }  

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

app.controller('myCtrl', function($scope) {

  $scope.page = 1;
  $scope.page2 = {value:1};
  
  $scope.alertPage = function() {
    alert($scope.page);
  }
  
  $scope.alertPage2 = function() {
    alert($scope.page2.value);
  }

})

app.directive('incrementer', function($timeout) {
  return {
   
    scope: {
      page: '=',
      alertPage: '&',
      page2:"=",
      alertPage2: '&'
    },
    template: '<button ng-click="incrementPage()">increment page</button>',

    link: function(scope, elem, attrs) {
      scope.incrementPage = function() {
          scope.page += 1;
          scope.page2.value += 1;
          $timeout(function(){ scope.alertPage() });
          scope.alertPage2();
      }
    }
  }
})

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
  <div incrementer page="page" alert-page="alertPage()" page2="page2" alert-page2="alertPage2()"></div>
  </div>

这篇关于更改指令中的控制器范围变量不会反映在控制器功能中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆