changing a controller scope variable in a directive is not reflected in controller function

前端 未结 4 483
傲寒
傲寒 2020-12-16 08:11

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()

相关标签:
4条回答
  • 2020-12-16 08:56

    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>

    0 讨论(0)
  • 2020-12-16 08:58

    You can pass the variable by reference, then the update will be immediate (because you wont copy it, but simply pass its location in memory).

    View:

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

    Directive:

    link: function(scope, elem, attrs) {
      scope.incrementPage = function() {
          scope.page.page += 1;
          scope.alertPage();
      }
    
    0 讨论(0)
  • 2020-12-16 09:01

    Try doing this slightly differently. Pass in a function to do the increment rather than incrementing inside the directive

    HTML

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

    Controller

              $scope.incPage = function() {    // Function to increment
                 $scope.page++;
             };
    

    In Directive

             scope: {
               page: '&',      // Receive like this
               alertPage: '&'
             },
    
    
              link: function(scope, elem, attrs) {
                   scope.incrementPage = function() {
                     scope.page();          // Call as function
                     scope.alertPage();
                   }  
              }
    
    0 讨论(0)
  • 2020-12-16 09:02

    The problem is that the timeline is off.

    1. button clicked, incrementPage()
    2. directive scope value incremented (now 2)
    3. alertPage() parent scope value read (still 1)
    4. parent scope updated as part of digest (now 2)

    To get around this, you need to either call the alert function after the digest cycle (e.g. $timeout) or you need to watch for changes in the parent scope.

    // in controller
    $scope.$watch('page', function (currentValue, previousValue) {
      // initially triggered with same value
      if (currentValue > previousValue) {
        alert(currentValue)
      }
    })
    

    Then change the value naturally.

    // in directive html
    <button ng-click="page = page + 1">
    
    0 讨论(0)
提交回复
热议问题