I have the following directive:
directive('yearSlider', function(Filter) {
return {
restrict: 'E', // must be an element
transclude: false, // don't preserve content
controller: function($scope) {
$scope.$watch('yearMin + yearMax', function(newVal, oldVal) {
if(newVal === oldVal) return; // skip initialization
$("#year-slider").slider("option", "min", parseInt($scope.yearMin));
$("#year-slider").slider("option", "max", parseInt($scope.yearMax));
$("#year-slider").slider("value", $("#year-slider").slider("value"));
});
},
link: function postLink($scope, $element) {
$element.slider({
range: true,
min: 1900,
max: new Date().getFullYear(),
values: [ 1900, new Date().getFullYear() ],
slide: function(event, ui) {
$scope.yearFrom = ui.values[0];
$scope.yearTo = ui.values[1];
$scope.$apply();
},
change: function(event, ui) {
$scope.yearFrom = ui.values[0];
$scope.yearTo = ui.values[1];
Filter.apply($scope);
}
});
},
template:
'<div id="year-slider"></div>',
replace: true
}
}).
This directive is used in a view and it renders a slider correctly.
I'm assigning both values of the slider to two models yearFrom
and yearTo
to get the range of years specified by the slider. In some cases, I need to change the min/max values of the slider and that's what I'm doing in the controller
above.
The issue here is that I'm watching for both values yearMin
and yearMax
and these two models change consecutively which leads to the controller and change
of $element.slider
executing twice.
What I'm trying to achieve is to execute this once but the fact that I have two models makes it logically impossible.
I figured it out while writing the question, I simply changed my model to:
$scope.years = { min: data.yearMin, max: data.yearMax }
And changed my $watch to:
$scope.$watch('years', function(newVal, oldVal) {
if(newVal === oldVal) return; // skip initialization
$("#year-slider").slider("option", "min", parseInt($scope.years.min));
$("#year-slider").slider("option", "max", parseInt($scope.years.max));
$("#year-slider").slider("value", $("#year-slider").slider("value"));
});
Putting JQuery slider aside, this is a common issue that faced me with AngularJS, particularly having many models firing multiple events to watchers while I needed them to fire once. I believe grouping them in a similar fashion (if applicable) would solve this issue.