Skip to content

Commit

Permalink
fix(slider): out of sync state between model and view value in same d…
Browse files Browse the repository at this point in the history
…igest cycle (angular#10980)

Fix out of sync state between model and view value that occurs in Slider when both model
and either min and/or max values are updated within the same digest cycle.
This is due to the $ngModelCtrl formatters kicking in and validating the view value before
the Slider directive $observer on the min and max attributes can fire.

Fixes angular#9125
  • Loading branch information
sviams authored and chmelevskij committed Jun 19, 2018
1 parent de00ac9 commit 5d5380d
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/components/slider/slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,13 @@ function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdThemi
var round;
function updateMin(value) {
min = parseFloat(value);
ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$modelValue, min, max);
element.attr('aria-valuemin', value);
updateAll();
}
function updateMax(value) {
max = parseFloat(value);
ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$modelValue, min, max);
element.attr('aria-valuemax', value);
updateAll();
}
Expand Down
156 changes: 156 additions & 0 deletions src/components/slider/slider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,162 @@ describe('md-slider', function() {
expect(pageScope.model).toBe(100);
});

describe('when raising max and model value equally beyond previous max simultaneously', function() {

var slider = null;

beforeEach(function() {
slider = setup('min="0" max="{{max}}" ng-model="model"');
pageScope.max = 5;
pageScope.model = 5;
pageScope.$apply();
expect(slider.attr('aria-valuenow')).toEqual('5');
expect(slider.attr('aria-valuemax')).toEqual('5');
pageScope.model = 6;
pageScope.max = 6;
pageScope.$apply();
});

it('should have updated max correctly', function () {
expect(slider.attr('aria-valuemax')).toEqual('6');
});

it('should have updated value correctly', function () {
expect(slider.attr('aria-valuenow')).toEqual('6');
});

});

describe('when raising max and model value beyond previous max simultaneously', function() {

var slider = null;

beforeEach(function() {
slider = setup('min="0" max="{{max}}" ng-model="model"');
pageScope.max = 4;
pageScope.model = 3;
pageScope.$apply();
expect(slider.attr('aria-valuenow')).toEqual('3');
expect(slider.attr('aria-valuemax')).toEqual('4');
pageScope.model = 6;
pageScope.max = 7;
pageScope.$apply();
});

it('should have updated max correctly', function () {
expect(slider.attr('aria-valuemax')).toEqual('7');
});

it('should have updated value correctly', function () {
expect(slider.attr('aria-valuenow')).toEqual('6');
});

});

describe('when raising max and setting model value below previous max simultaneously', function() {

var slider = null;

beforeEach(function() {
slider = setup('min="0" max="{{max}}" ng-model="model"');
pageScope.max = 4;
pageScope.model = 2;
pageScope.$apply();
expect(slider.attr('aria-valuenow')).toEqual('2');
expect(slider.attr('aria-valuemax')).toEqual('4');
pageScope.model = 3;
pageScope.max = 5;
pageScope.$apply();
});

it('should have updated max correctly', function () {
expect(slider.attr('aria-valuemax')).toEqual('5');
});

it('should have updated value correctly', function () {
expect(slider.attr('aria-valuenow')).toEqual('3');
});

});

describe('when lowering min and model value equally below previous min simultaneously', function() {

var slider = null;

beforeEach(function() {
slider = setup('min="{{min}}" max="10" ng-model="model"');
pageScope.min = 5;
pageScope.model = 5;
pageScope.$apply();
expect(slider.attr('aria-valuenow')).toEqual('5');
expect(slider.attr('aria-valuemin')).toEqual('5');
pageScope.model = 2;
pageScope.min = 2;
pageScope.$apply();
});

it('should have updated min correctly', function () {
expect(slider.attr('aria-valuemin')).toEqual('2');
});

it('should have updated value correctly', function () {
expect(slider.attr('aria-valuenow')).toEqual('2');
});

});

describe('when lowering min and model value below previous min simultaneously', function() {

var slider = null;

beforeEach(function() {
slider = setup('min="{{min}}" max="10" ng-model="model"');
pageScope.min = 5;
pageScope.model = 6;
pageScope.$apply();
expect(slider.attr('aria-valuenow')).toEqual('6');
expect(slider.attr('aria-valuemin')).toEqual('5');
pageScope.model = 3;
pageScope.min = 2;
pageScope.$apply();
});

it('should have updated min correctly', function () {
expect(slider.attr('aria-valuemin')).toEqual('2');
});

it('should have updated value correctly', function () {
expect(slider.attr('aria-valuenow')).toEqual('3');
});

});

describe('when lowering min and setting model value above previous min simultaneously', function() {

var slider = null;

beforeEach(function() {
slider = setup('min="{{min}}" max="10" ng-model="model"');
pageScope.min = 5;
pageScope.model = 7;
pageScope.$apply();
expect(slider.attr('aria-valuenow')).toEqual('7');
expect(slider.attr('aria-valuemin')).toEqual('5');
pageScope.model = 6;
pageScope.min = 2;
pageScope.$apply();
});

it('should have updated min correctly', function () {
expect(slider.attr('aria-valuemin')).toEqual('2');
});

it('should have updated value correctly', function () {
expect(slider.attr('aria-valuenow')).toEqual('6');
});

});

it('should update the thumb text', function() {
var slider = setup('ng-model="value" md-discrete min="0" max="100" step="1"');
var wrapper = getWrapper(slider);
Expand Down

0 comments on commit 5d5380d

Please sign in to comment.