Skip to content

Commit 67e02b0

Browse files
amcdnljelbourn
authored andcommitted
fix(tabs): fix infinite tab loop (#6663)
Fixes #4639
1 parent 9acab86 commit 67e02b0

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

src/lib/tabs/tab-group.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,25 @@ describe('MdTabGroup', () => {
7070
});
7171
}));
7272

73+
it('should set to correct tab on fast change', async(() => {
74+
let component = fixture.componentInstance;
75+
component.selectedIndex = 0;
76+
fixture.detectChanges();
77+
78+
setTimeout(() => {
79+
component.selectedIndex = 1;
80+
fixture.detectChanges();
81+
82+
setTimeout(() => {
83+
component.selectedIndex = 0;
84+
fixture.detectChanges();
85+
fixture.whenStable().then(() => {
86+
expect(component.selectedIndex).toBe(0);
87+
});
88+
}, 1);
89+
}, 1);
90+
}));
91+
7392
it('should change tabs based on selectedIndex', fakeAsync(() => {
7493
let component = fixture.componentInstance;
7594
let tabComponent = fixture.debugElement.query(By.css('md-tab-group')).componentInstance;

src/lib/tabs/tab-group.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import {
2525
ViewEncapsulation,
2626
} from '@angular/core';
2727
import {coerceBooleanProperty} from '@angular/cdk/coercion';
28-
import {map} from '@angular/cdk/rxjs';
29-
import {Observable} from 'rxjs/Observable';
3028
import {Subscription} from 'rxjs/Subscription';
3129
import {MdTab} from './tab';
3230
import {merge} from 'rxjs/observable/merge';
@@ -131,9 +129,7 @@ export class MdTabGroup extends _MdTabGroupMixinBase implements AfterContentInit
131129
private _backgroundColor: ThemePalette;
132130

133131
/** Output to enable support for two-way binding on `[(selectedIndex)]` */
134-
@Output() get selectedIndexChange(): Observable<number> {
135-
return map.call(this.selectChange, event => event.index);
136-
}
132+
@Output() selectedIndexChange: EventEmitter<number> = new EventEmitter();
137133

138134
/** Event emitted when focus has changed within a tab group. */
139135
@Output() focusChange: EventEmitter<MdTabChangeEvent> = new EventEmitter<MdTabChangeEvent>();
@@ -157,16 +153,20 @@ export class MdTabGroup extends _MdTabGroupMixinBase implements AfterContentInit
157153
* a new selected tab should transition in (from the left or right).
158154
*/
159155
ngAfterContentChecked(): void {
160-
// Clamp the next selected index to the bounds of 0 and the tabs length. Note the `|| 0`, which
161-
// ensures that values like NaN can't get through and which would otherwise throw the
162-
// component into an infinite loop (since Math.max(NaN, 0) === NaN).
156+
// Clamp the next selected index to the boundsof 0 and the tabs length.
157+
// Note the `|| 0`, which ensures that values like NaN can't get through
158+
// and which would otherwise throw the component into an infinite loop
159+
// (since Math.max(NaN, 0) === NaN).
163160
let indexToSelect = this._indexToSelect =
164161
Math.min(this._tabs.length - 1, Math.max(this._indexToSelect || 0, 0));
165162

166163
// If there is a change in selected index, emit a change event. Should not trigger if
167164
// the selected index has not yet been initialized.
168165
if (this._selectedIndex != indexToSelect && this._selectedIndex != null) {
169166
this.selectChange.emit(this._createChangeEvent(indexToSelect));
167+
// Emitting this value after change detection has run
168+
// since the checked content may contain this variable'
169+
Promise.resolve().then(() => this.selectedIndexChange.emit(indexToSelect));
170170
}
171171

172172
// Setup the position for each tab and optionally setup an origin on the next selected tab.

0 commit comments

Comments
 (0)