@schurin
Люблю катать с гор, особенно на санках

Как насильно вызвать $watch в директиве?

Всем привет!
Столкнулся с тем, что код директивы которая отображается после клика срабатывает раньше чем $watch в другой директиве, хотелось бы наоборот.
$watch про который я сказал чуть выше и директива которая отрабатывает раньше связаны элементом модели, который и управляет переключение, по коду думаю будет понятней о чем говорю.

По клику открывается панель истории в которой есть слайдер с ползунком, для простоты я их упустил, плюс в панели много всего и ширины экрана иногда не хватает на слайдер.
<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>

Стал писать директиву, лишь для одной цели подгонять элементы истории под ширину экрана:
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;
						}
				});
			}
		}
	});
});

Код контроллера:
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'
				}
			};
		}]);
});

и код 2й директивы, которая отвечает за сам слайдер:
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);
				}
			}

		}]);
});


После срабатывания ng-click попадаем в директиву slider, задаём ширину для ползунка слайдера
И только потом попадаем в $watch директивы overflowHeader
Как при изменении переменной $scope.mode сделать всё наоборот, сначала $watch и лишь затем директива slider, да и собственно почему так происходит, ведь переменную модели мы изменили, ng-if отработал т.к. в директиву слайдера мы попали, кто отвечает за этот порядок?
  • Вопрос задан
  • 242 просмотра
Пригласить эксперта
Ответы на вопрос 1
@lega
Вы можете сделать ф-ию в директиве $scope.recalc(), и вызывать её до или после клика ng-click="ctrl.historyMode(); recalc();", таким образом выкините лишний watch, хотя это костыль.

Либо для ngIf можно завести отдельную переменную, которую менять уже в директиве, таким образом ngIf будет срабатывать после, но это увеличивает ttl $digest.

Вообще ваш watch должен срабатывать раньше чем ngIf, но ангуляр не дает на это гарантии.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы