$watch to monitor change in class on directive firing 1 cycle late

泪湿孤枕 提交于 2019-12-13 17:20:44

问题


My goal is to do some action when a particular directive receives the class 'focused' through ng-class. But watching for changes on each of the directives seems to be doing weird things I don't understand. Here is the code first:

http://plnkr.co/edit/6Te8O2mlBI058DpwGF7f?p=preview

index.html

   <test-question
      ng-class="{'focused': tracer.focus == 1}"
      focusnum = "{{n}}"
      ng-click="tracer.focus = 1"
      >
      Test Question 1
    </test-question>
    <test-question
      ng-class="{'focused': tracer.focus == 2}"
      focusnum = "{{n}}"
      ng-click="tracer.focus = 2"
      >
      Test Question 2
    </test-question>
    <test-question
      ng-class="{'focused': tracer.focus == 3}"
      focusnum = "{{n}}"
      ng-click="tracer.focus = 3"
      >
      Test Question 3
    </test-question>

script.js

angular.module('sampleApp', [])
  .controller("SampleController", function($scope) {
    $scope.tracer = {
        focus: 1
    }
  })
  .directive('testQuestion', function() {
    return {
        restrict: 'E',
        link: function($scope, el, attrs) {
          $scope.$watch(function() {
                  return el.attr('class');
              }, function(newValue, oldValue) {
                  // do something here when directive gets class focused
                  console.log("text", el.text());
                  console.log("newValue", newValue);
                  console.log("oldValue", oldValue);
            });
        }
    }
  });

Initially the first test question is highlighted. When you click the second question I expect the console to log

"text" Test Question 1 "newValue" undefined "oldValue" focused "text" Test Question 2 "newValue" focused "oldValue" undefined

However the console actually logs

"text" Test Question 1 "newValue" focused "oldValue" undefined

As a result, of this weird behavior I cannot accurately detect when a directive receives the class focused. It appears as if the watch is one cycle late. It would be great if a fellow friend could help me understand why this is happening. Thank you!

Additional

After I click question 2, and if I subsequently click question 3 the console logs

"text" Test Question 1 "newValue" "oldValue" focused "text" Test Question 2 "newValue" focused "oldValue" undefined


回答1:


Yes is become late, there is no proper solution for this condition yet. However you can do something below.

    $scope.$watch(function() {
              return el.hasClass('focused');
          }, function(newValue, oldValue) {
              // now you should use javascript setTimeout for check after $diggest
              var myOldValue = newValue; //this mean newValue realy oldValue yet.
               setTimeout(function(){
                 var myNewValue= el.hasClass('focused');
                  console.log(myNewValue, myOldValue)
                  //do staff here
               },0)
              //note that, don't use angular $timeout it may couse recursive stack
        });

WHY?

Because you are watching an async event which outside of AngularJS. Namely need to called at the end, to tell AngularJS that an asynchronous event just occurred by using $scope.$apply().

This like our custom $('button').on('click', ...) events which need to $scope.$apply(). However you may ask that, I am watching changes done by using ng-class. This is rigth, but your watcher function is called before ng-class done its work. Namely you aren't watching "ng-class" you are watching class attribute. For this reason the changes you are listen will noticed to angular in the next diggest.

If you tried to access current class in your watcher, you will get old value, because ng-class hasn't done its work yet.

If you tried to access current class javascript setTimeout function in your in your watcher, you will get the correct vallue, because setTimeout would be called after all angular works done.

This case is valid for all changes outside of AngularJS. When you tried to watch an element heigth, width, color, an object property etc. You can use it in quietness.

NOTE Think watching changes outside of AngularJS like a promise and setTimeout would be your callback.



来源:https://stackoverflow.com/questions/27786814/watch-to-monitor-change-in-class-on-directive-firing-1-cycle-late

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!