A
A
Artem Shchurin2016-01-14 17:13:14
Angular
Artem Shchurin, 2016-01-14 17:13:14

How to forcefully call $watch in a directive?

Hello!
Faced with the fact that the code of the directive that is displayed after the click is triggered earlier than $watch in another directive, I would like it to be the other way around.
$ watch about which I said a little higher and the directive that works out earlier are connected with the model element that controls the switch, I think it will be clearer about what I'm talking about in the code.
On click, a history panel opens in which there is a slider with a slider, for simplicity I missed them, plus there is a lot of things in the panel and sometimes the screen width is not enough for the slider.

<div ng-controller="HeaderCtrl as ctrl" overflow-header>
<div class="toogle-mode" ng-click="ctrl.historyMode()"></div>
    <div class="history" ng-if="mode === 'history'">
        <div slider class="slider"></div>
    </div>
</div>

I began to write a directive, for only one purpose, to fit the elements of the story to the width of the screen:
define(['app'], function(app) {
  app.directive('overflowHeader', function() {
    return {
      restrict: 'A',
      scope: true,
      link: function($scope, element) {

        $scope.$watch('mode', function(newVal, oldVal) {
            switch(newVal) {
              case 'history':
                //тут делаем расчёты, вписались или нет
//добавляем класс элементу
                break;
              default :
                //вернём всё на место
                break;
            }
        });
      }
    }
  });
});

Controller code:
define(['app', 'overflowHeader'], function(app) {
  app.controller('HeaderCtrl', ['$scope', 'params', 'modal', 'dict',
    function($scope, params, modal, dict) {
      this.historyMode = function() {
        if($scope.mode === 'history') {
          $scope.mode = 'init'
        }else {
          $scope.mode = 'history'
        }
      };
    }]);
});

and the code of the 2nd directive, which is responsible for the slider itself:
define(['angular'], function(angular) {
  angular.module('ids.slider', ['ids.resources.service'])
    .directive('slider', ['$document', 'resources', 'outerConfig', function($document) {
      return {
        restrict: 'A',
        replace: true,
        templateUrl: outerConfig.baseUrl + 'common/directives/slider/tpl.html',
        controllerAs: 'ctrl',
        controller: ['$scope', '$attrs', '$parse', function($scope, $attrs, $parse) {
          this.setWidth = function(val) {
            // тут задаём ширину ползунка
          };
        }],
        link: function(scope, element, attrs, ctrl) {
          ctrl.setWidth(element[0].offsetWidth - 32);
        }
      }

    }]);
});

After the ng-click is triggered, we get into the slider directive, set the width for the slider slider
And only then we get into the $watch of the overflowHeader directive
How to do the opposite when changing the $scope.mode variable, first $watch and only then the slider directive, and actually why happens, because we changed the model variable, ng-if worked because we got into the slider directive, who is responsible for this order?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
L
lega, 2016-01-14
@lega

You can make a function in the $scope.recalc() directive, and call it before or after the click ng-click="ctrl.historyMode(); recalc();", thus throwing out the extra watch, although this is a crutch.
Or, for ngIf, you can create a separate variable that can be changed already in the directive, so ngIf will work after, but this increases the ttl $digest.
In general, your watch should fire before ngIf, but angular does not guarantee this.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question