@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, но ангуляр не дает на это гарантии.
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы