Skip to content

Commit 1ae81a4

Browse files
crisbetotinayuangao
authored andcommitted
fix(progress-spinner): not redrawing when changing modes (#3672)
* Fixes the progress spinner not redrawing when the mode is changed dynamically from `indeterminate` to `determinate`. * Some minor cleanup in the progress spinner. Fixes #3648.
1 parent 038a337 commit 1ae81a4

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

src/demo-app/progress-spinner/progress-spinner-demo.html

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ <h1>Determinate</h1>
44
<p>Value: {{progressValue}}</p>
55
<button md-raised-button (click)="step(10)">Increase</button>
66
<button md-raised-button (click)="step(-10)">Decrease</button>
7+
<md-checkbox [(ngModel)]="modeToggle">Is determinate</md-checkbox>
78
</div>
89

910
<div class="demo-progress-spinner">
10-
<md-progress-spinner mode="determinate" [value]="progressValue" color="primary"></md-progress-spinner>
11-
<md-progress-spinner [value]="progressValue" color="accent"></md-progress-spinner>
11+
<md-progress-spinner [mode]="modeToggle ? 'indeterminate' : 'determinate'"
12+
[value]="progressValue" color="primary"></md-progress-spinner>
13+
<md-progress-spinner [mode]="modeToggle ? 'indeterminate' : 'determinate'"
14+
[value]="progressValue" color="accent"></md-progress-spinner>
1215
</div>
1316

1417
<h1>Indeterminate</h1>
@@ -24,3 +27,4 @@ <h1>Indeterminate</h1>
2427
<md-progress-spinner mode="indeterminate" [color]="color"></md-progress-spinner>
2528
<md-spinner [color]="color"></md-spinner>
2629
</div>
30+

src/demo-app/progress-spinner/progress-spinner-demo.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import {Component} from '@angular/core';
88
styleUrls: ['progress-spinner-demo.css'],
99
})
1010
export class ProgressSpinnerDemo {
11-
progressValue: number = 40;
11+
progressValue: number = 60;
1212
color: string = 'primary';
13+
modeToggle: boolean = false;
1314

1415
step(val: number) {
1516
this.progressValue = Math.max(0, Math.min(100, val + this.progressValue));

src/lib/progress-spinner/progress-spinner.spec.ts

+26-9
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ describe('MdProgressSpinner', () => {
5050
it('should set the value to undefined when the mode is set to indeterminate', () => {
5151
let fixture = TestBed.createComponent(ProgressSpinnerWithValueAndBoundMode);
5252
let progressElement = fixture.debugElement.query(By.css('md-progress-spinner'));
53-
fixture.debugElement.componentInstance.mode = 'determinate';
53+
fixture.componentInstance.mode = 'determinate';
5454
fixture.detectChanges();
5555

5656
expect(progressElement.componentInstance.value).toBe(50);
57-
fixture.debugElement.componentInstance.mode = 'indeterminate';
57+
fixture.componentInstance.mode = 'indeterminate';
5858
fixture.detectChanges();
5959
expect(progressElement.componentInstance.value).toBe(undefined);
6060
});
@@ -89,7 +89,7 @@ describe('MdProgressSpinner', () => {
8989
let progressElement = fixture.debugElement.query(By.css('md-progress-spinner'));
9090
expect(progressElement.componentInstance.interdeterminateInterval).toBeTruthy();
9191

92-
fixture.debugElement.componentInstance.isHidden = true;
92+
fixture.componentInstance.isHidden = true;
9393
fixture.detectChanges();
9494
expect(progressElement.componentInstance.interdeterminateInterval).toBeFalsy();
9595
});
@@ -102,7 +102,7 @@ describe('MdProgressSpinner', () => {
102102

103103
expect(progressElement.componentInstance.interdeterminateInterval).toBeTruthy();
104104

105-
fixture.debugElement.componentInstance.isHidden = true;
105+
fixture.componentInstance.isHidden = true;
106106
fixture.detectChanges();
107107

108108
expect(progressElement.componentInstance.interdeterminateInterval).toBeFalsy();
@@ -116,7 +116,7 @@ describe('MdProgressSpinner', () => {
116116

117117
expect(progressElement.nativeElement.classList).toContain('mat-primary');
118118

119-
fixture.debugElement.componentInstance.color = 'accent';
119+
fixture.componentInstance.color = 'accent';
120120
fixture.detectChanges();
121121

122122
expect(progressElement.nativeElement.classList).toContain('mat-accent');
@@ -131,13 +131,30 @@ describe('MdProgressSpinner', () => {
131131

132132
expect(progressElement.nativeElement.classList).toContain('mat-primary');
133133

134-
fixture.debugElement.componentInstance.color = 'accent';
134+
fixture.componentInstance.color = 'accent';
135135
fixture.detectChanges();
136136

137137
expect(progressElement.nativeElement.classList).toContain('mat-accent');
138138
expect(progressElement.nativeElement.classList).not.toContain('mat-primary');
139139
});
140140

141+
it('should re-render the circle when switching from indeterminate to determinate mode', () => {
142+
let fixture = TestBed.createComponent(ProgressSpinnerWithValueAndBoundMode);
143+
let progressElement = fixture.debugElement.query(By.css('md-progress-spinner')).nativeElement;
144+
145+
fixture.componentInstance.mode = 'indeterminate';
146+
fixture.detectChanges();
147+
148+
let path = progressElement.querySelector('path');
149+
let oldDimesions = path.getAttribute('d');
150+
151+
fixture.componentInstance.mode = 'determinate';
152+
fixture.detectChanges();
153+
154+
expect(path.getAttribute('d')).not
155+
.toBe(oldDimesions, 'Expected circle dimensions to have changed.');
156+
});
157+
141158
});
142159

143160

@@ -148,14 +165,14 @@ class BasicProgressSpinner { }
148165
class IndeterminateProgressSpinner { }
149166

150167
@Component({template: '<md-progress-spinner value="50" [mode]="mode"></md-progress-spinner>'})
151-
class ProgressSpinnerWithValueAndBoundMode { }
168+
class ProgressSpinnerWithValueAndBoundMode { mode = 'indeterminate'; }
152169

153170
@Component({template: `
154171
<md-progress-spinner mode="indeterminate" *ngIf="!isHidden"></md-progress-spinner>`})
155-
class IndeterminateProgressSpinnerWithNgIf { }
172+
class IndeterminateProgressSpinnerWithNgIf { isHidden = false; }
156173

157174
@Component({template: `<md-spinner *ngIf="!isHidden"></md-spinner>`})
158-
class SpinnerWithNgIf { }
175+
class SpinnerWithNgIf { isHidden = false; }
159176

160177
@Component({template: `<md-spinner [color]="color"></md-spinner>`})
161178
class SpinnerWithColor { color: string = 'primary'; }

src/lib/progress-spinner/progress-spinner.ts

+13-10
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export class MdProgressSpinner implements OnDestroy {
134134
set value(v: number) {
135135
if (v != null && this.mode == 'determinate') {
136136
let newValue = clamp(v);
137-
this._animateCircle((this.value || 0), newValue, linearEase, DURATION_DETERMINATE, 0);
137+
this._animateCircle(this.value || 0, newValue);
138138
this._value = newValue;
139139
}
140140
}
@@ -150,13 +150,16 @@ export class MdProgressSpinner implements OnDestroy {
150150
get mode() {
151151
return this._mode;
152152
}
153-
set mode(m: ProgressSpinnerMode) {
154-
if (m == 'indeterminate') {
155-
this._startIndeterminateAnimation();
156-
} else {
157-
this._cleanupIndeterminateAnimation();
153+
set mode(mode: ProgressSpinnerMode) {
154+
if (mode !== this._mode) {
155+
if (mode === 'indeterminate') {
156+
this._startIndeterminateAnimation();
157+
} else {
158+
this._cleanupIndeterminateAnimation();
159+
this._animateCircle(0, this._value);
160+
}
161+
this._mode = mode;
158162
}
159-
this._mode = m;
160163
}
161164

162165
constructor(
@@ -176,8 +179,8 @@ export class MdProgressSpinner implements OnDestroy {
176179
* @param rotation The starting angle of the circle fill, with 0° represented at the top center
177180
* of the circle.
178181
*/
179-
private _animateCircle(animateFrom: number, animateTo: number, ease: EasingFn,
180-
duration: number, rotation: number) {
182+
private _animateCircle(animateFrom: number, animateTo: number, ease: EasingFn = linearEase,
183+
duration = DURATION_DETERMINATE, rotation = 0) {
181184

182185
let id = ++this._lastAnimationId;
183186
let startTime = Date.now();
@@ -246,7 +249,7 @@ export class MdProgressSpinner implements OnDestroy {
246249
* Renders the arc onto the SVG element. Proxies `getArc` while setting the proper
247250
* DOM attribute on the `<path>`.
248251
*/
249-
private _renderArc(currentValue: number, rotation: number) {
252+
private _renderArc(currentValue: number, rotation = 0) {
250253
// Caches the path reference so it doesn't have to be looked up every time.
251254
let path = this._path = this._path || this._elementRef.nativeElement.querySelector('path');
252255

0 commit comments

Comments
 (0)