I'm trying to watch a controller's properties from it's associated directive from within the link function. The controller itself is set to the 'window' object on the $scope using controllerAs; here is the directive definition:
function windowDirective() {
return {
transclude: true,
template: template,
restrict: 'E',
controller: WindowCtrl,
controllerAs: 'window',
link: function($scope, $element, $attrs, $ctrl) {
$scope.$watch('window.x', function(newValue, oldValue) {
// access x here
});
}
};
}
And here is WindowCtrl
'use strict';
class WindowCtrl {
move(x, y) {
this.x = x;
this.y = y;
}
}
module.exports = WindowCtrl;
move(x, y)
is being called when I drag on a child directive - it is definitely being called and this.x
and this.y
are definitely being set on WindowCtrl. In addition, if I console.dir
the $scope
then fire move()
a few times, I can open up the scope in chrome (because it's lazily evaluated) and see that $scope.window.x
and $scope.window.y
are indeed being set.
However, my $scope.$watch
never actually fires aside from when it initially detects that window.x
is undefined. Not really sure how to proceed. I did search and try all of the solutions I found but none of them seemed to have worked.
I'm using Angular 1.3.16.
NB: The access to WindowCtrl.move()
is only ever from within Angular's digest cycle - see below - however using $scope.$apply()
solves this. I'm not sure why this is the case. Could you explain? The below is a directive which is nested inside of the above directive. It will invoke the method at onDrag
, which in my example points to window.move(x, y);
function windowHeaderDirective() {
return {
transclude: true,
template: template,
replace: true,
require: `^${windowDirective.$name}`,
scope: {
enableClose: '=actionClose',
draggable: '=',
onDrag: '&'
},
bindToController: true,
link: function($scope, $element, $attrs, $ctrl) {
$scope.close = $ctrl.close.bind($ctrl);
let moving = false;
$element.on('mousemove', function(event) {
if(!moving) return
const { x, y } = event;
$scope.header.onDrag({ x, y });
// $scope.$apply here will fix this issue, but why? Isn't $element.on within angular's digest cycle??
});
$element.on('mousedown', function(event) {
moving = true;
});
$element.on('mouseup', function(event) {
moving = false
});
},
controller: controller,
controllerAs: 'header'
};
}
In the $watch try using a function watcher like this:
$scope.$watch(function() {
return $scope.window.x
}, ...
Self answer:
It appears, due to my update, I answered the question myself, so;
$element.on
does not appear to actually be in the angular digest cycle - this is fairly surprising for me, I assumed it would be. However, this essentially means that my code works as it should - it's just the changes to the variables on the controller are not apparent straight away. The way to fix this is to simply use either ng-mousedown
et al, or $scope.$apply
in the $element.on
handler.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.