Skip to content

Commit 106a4b4

Browse files
committed
fix(tabs): adding the selection refactoring #5471
1 parent ac51c0d commit 106a4b4

File tree

5 files changed

+164
-210
lines changed

5 files changed

+164
-210
lines changed

projects/igniteui-angular/src/lib/tabs/tab-item.component.ts

Lines changed: 14 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { IgxTabItemTemplateDirective } from './tabs.directives';
1818
templateUrl: 'tab-item.component.html'
1919
})
2020

21-
export class IgxTabItemComponent implements IgxTabItemBase {
21+
export class IgxTabItemComponent extends IgxTabItemBase {
2222

2323
/**
2424
* Gets the group associated with the tab.
@@ -80,10 +80,10 @@ export class IgxTabItemComponent implements IgxTabItemBase {
8080

8181
private _nativeTabItem: ElementRef;
8282
private _changesCount = 0; // changes and updates accordingly applied to the tab.
83-
private _isSelected = false;
8483
private _disabled = false;
8584

8685
constructor(private _tabs: IgxTabsBase, private _element: ElementRef) {
86+
super();
8787
this._nativeTabItem = _element;
8888
}
8989

@@ -158,9 +158,7 @@ export class IgxTabItemComponent implements IgxTabItemBase {
158158
@HostListener('window:resize', ['$event'])
159159
public onResize(event) {
160160
if (this.isSelected) {
161-
this._tabs.selectedIndicator.nativeElement.style.visibility = 'visible';
162-
this._tabs.selectedIndicator.nativeElement.style.width = `${this.nativeTabItem.nativeElement.offsetWidth}px`;
163-
this._tabs.selectedIndicator.nativeElement.style.transform = `translate(${this.nativeTabItem.nativeElement.offsetLeft}px)`;
161+
this._tabs.transformIndicatorAnimation(this.nativeTabItem.nativeElement);
164162
}
165163
}
166164

@@ -241,63 +239,28 @@ export class IgxTabItemComponent implements IgxTabItemBase {
241239
return this.relatedGroup ? this.relatedGroup.isSelected : this._isSelected;
242240
}
243241
set isSelected(newValue: boolean) {
244-
if (this.relatedGroup) {
245-
this.relatedGroup.isSelected = newValue;
246-
} else if (this._isSelected !== newValue) {
247-
this._isSelected = newValue;
248-
if (this._isSelected) {
249-
this.select();
250-
}
242+
if (!this.disabled && this.isSelected !== newValue) {
243+
this._tabs.performSelectionChange(newValue ? this : null);
251244
}
252245
}
253246

254247
/**
255248
* @hidden
256249
*/
257-
get index(): number {
258-
if (this._tabs.tabs) {
259-
return this._tabs.tabs.toArray().indexOf(this);
250+
public select(): void {
251+
if (!this.disabled && !this.isSelected) {
252+
this._tabs.performSelectionChange(this);
260253
}
261254
}
262255

263256
/**
264257
* @hidden
265258
*/
266-
public select(focusDelay = 200): void {
267-
if (this.relatedGroup) {
268-
this.relatedGroup.select(focusDelay);
269-
} else {
270-
this._isSelected = true;
271-
this._tabs.onTabItemSelected.emit({ tab: this, group: null });
272-
this.handleTabSelectionAnimation();
273-
}
274-
}
275-
276-
private handleTabSelectionAnimation(): void {
277-
const tabElement = this.nativeTabItem.nativeElement;
278-
279-
// Scroll to the left
280-
if (tabElement.offsetLeft < this._tabs.offset) {
281-
this._tabs.scrollElement(tabElement, false);
282-
}
283-
284-
// Scroll to the right
285-
const viewPortOffsetWidth = this._tabs.viewPort.nativeElement.offsetWidth;
286-
const delta = (tabElement.offsetLeft + tabElement.offsetWidth) - (viewPortOffsetWidth + this._tabs.offset);
287-
// Fix for IE 11, a difference is accumulated from the widths calculations
288-
if (delta > 1) {
289-
this._tabs.scrollElement(tabElement, true);
290-
}
291-
292-
this.transformIndicatorAnimation(tabElement);
293-
}
294-
295-
private transformIndicatorAnimation(element: HTMLElement): void {
296-
if (this._tabs && this._tabs.selectedIndicator) {
297-
this._tabs.selectedIndicator.nativeElement.style.visibility = `visible`;
298-
this._tabs.selectedIndicator.nativeElement.style.width = `${element.offsetWidth}px`;
299-
this._tabs.selectedIndicator.nativeElement.style.transform = `translate(${element.offsetLeft}px)`;
259+
get index(): number {
260+
if (this._tabs.tabs) {
261+
return this._tabs.tabs.toArray().indexOf(this);
300262
}
263+
return -1;
301264
}
302265

303266
private onKeyDown(isLeftArrow: boolean, index = null): void {
@@ -308,7 +271,7 @@ export class IgxTabItemComponent implements IgxTabItemBase {
308271
: (this._tabs.selectedIndex === tabsArray.length - 1) ? 0 : this._tabs.selectedIndex + 1;
309272
}
310273
const tab = tabsArray[index];
311-
tab.select(200);
274+
tab.select();
312275
}
313276

314277
/**
@@ -330,4 +293,5 @@ export class IgxTabItemComponent implements IgxTabItemBase {
330293
public get context(): any {
331294
return this.relatedGroup ? this.relatedGroup : this;
332295
}
296+
333297
}

projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts

Lines changed: 11 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ import { IgxTabsBase, IgxTabsGroupBase } from './tabs.common';
1919
templateUrl: 'tabs-group.component.html'
2020
})
2121

22-
export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit, AfterViewChecked {
23-
24-
/**
25-
* @hidden
26-
*/
27-
private _isSelected = false;
22+
export class IgxTabsGroupComponent extends IgxTabsGroupBase implements AfterContentInit, AfterViewChecked {
2823

2924
/**
3025
* An @Input property that allows you to enable/disable the `IgxTabGroupComponent`.
@@ -68,12 +63,8 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
6863
return this._isSelected;
6964
}
7065
public set isSelected(newValue: boolean) {
71-
if (this._isSelected !== newValue) {
72-
if (newValue) {
73-
this.select();
74-
} else {
75-
this._isSelected = newValue;
76-
}
66+
if (!this.disabled && this.isSelected !== newValue) {
67+
this._tabs.performSelectionChange(newValue ? this.relatedTab : null);
7768
}
7869
}
7970

@@ -86,6 +77,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
8677
private _tabTemplate: TemplateRef<any>;
8778

8879
constructor(private _tabs: IgxTabsBase, private _element: ElementRef) {
80+
super();
8981
}
9082

9183
/**
@@ -103,7 +95,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
10395
@HostListener('window:resize', ['$event'])
10496
public onResize(event) {
10597
if (this.isSelected) {
106-
this.transformContentAnimation(0);
98+
this._tabs.transformContentAnimation(this.relatedTab, 0);
10799
}
108100
}
109101

@@ -137,6 +129,7 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
137129
if (this._tabs.groups) {
138130
return this._tabs.groups.toArray().indexOf(this);
139131
}
132+
return -1;
140133
}
141134

142135
/**
@@ -171,8 +164,8 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
171164

172165
if (this.isSelected) {
173166
const tabItem = this.relatedTab.nativeTabItem.nativeElement;
174-
this.transformContentAnimation(0);
175-
this.transformIndicatorAnimation(tabItem);
167+
this._tabs.transformContentAnimation(this.relatedTab, 0);
168+
this._tabs.transformIndicatorAnimation(tabItem);
176169
}
177170
}
178171

@@ -188,51 +181,10 @@ export class IgxTabsGroupComponent implements IgxTabsGroupBase, AfterContentInit
188181
*```
189182
* @param focusDelay A number representing the expected delay.
190183
*/
191-
public select(focusDelay = 200): void {
192-
if (this.disabled || this.isSelected) {
193-
return;
184+
public select(): void {
185+
if (!this.disabled && !this.isSelected) {
186+
this._tabs.performSelectionChange(this.relatedTab);
194187
}
195-
196-
this._isSelected = true;
197-
this.relatedTab.tabindex = 0;
198-
199-
if (focusDelay !== 0) {
200-
setTimeout(() => {
201-
this.relatedTab.nativeTabItem.nativeElement.focus();
202-
}, focusDelay);
203-
}
204-
this.handleSelection();
205-
this._tabs.onTabItemSelected.emit({ tab: this._tabs.tabs.toArray()[this.index], group: this });
206188
}
207189

208-
private handleSelection(): void {
209-
const tabElement = this.relatedTab.nativeTabItem.nativeElement;
210-
211-
// Scroll to the left
212-
if (tabElement.offsetLeft < this._tabs.offset) {
213-
this._tabs.scrollElement(tabElement, false);
214-
}
215-
216-
// Scroll to the right
217-
const viewPortOffsetWidth = this._tabs.viewPort.nativeElement.offsetWidth;
218-
const delta = (tabElement.offsetLeft + tabElement.offsetWidth) - (viewPortOffsetWidth + this._tabs.offset);
219-
// Fix for IE 11, a difference is accumulated from the widths calculations
220-
if (delta > 1) {
221-
this._tabs.scrollElement(tabElement, true);
222-
}
223-
224-
this.transformContentAnimation(0.2);
225-
this.transformIndicatorAnimation(tabElement);
226-
}
227-
228-
private transformContentAnimation(duration: number): void {
229-
const contentOffset = this._tabs.tabsContainer.nativeElement.offsetWidth * this.index;
230-
this._tabs.contentsContainer.nativeElement.style.transitionDuration = `${duration}s`;
231-
this._tabs.contentsContainer.nativeElement.style.transform = `translate(${-contentOffset}px)`;
232-
}
233-
234-
private transformIndicatorAnimation(element: HTMLElement): void {
235-
this._tabs.selectedIndicator.nativeElement.style.width = `${element.offsetWidth}px`;
236-
this._tabs.selectedIndicator.nativeElement.style.transform = `translate(${element.offsetLeft}px)`;
237-
}
238190
}

projects/igniteui-angular/src/lib/tabs/tabs.common.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,22 @@ export abstract class IgxTabsBase {
1515
onTabItemSelected: EventEmitter<{}>; // TODO: Define event arg interface!
1616
hasContentTabs: boolean;
1717
scrollElement(element: any, scrollRight: boolean) {}
18+
performSelectionChange(newTab: IgxTabItemBase) {}
19+
transformContentAnimation(tab: IgxTabItemBase, duration: number) {}
20+
transformIndicatorAnimation(element: HTMLElement) {}
1821
}
1922

2023
/** @hidden */
21-
export interface IgxTabItemBase {
24+
export abstract class IgxTabItemBase {
2225
nativeTabItem: ElementRef;
23-
select(focusDelay?: number);
26+
_isSelected = false;
27+
tabindex;
28+
select(focusDelay?: number): void {}
29+
get index(): number { return 0; }
2430
}
2531

2632
/** @hidden */
27-
export interface IgxTabsGroupBase {
28-
select(focusDelay?: number);
33+
export abstract class IgxTabsGroupBase {
34+
_isSelected = false;
35+
select(focusDelay?: number): void {}
2936
}

projects/igniteui-angular/src/lib/tabs/tabs.component.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -578,16 +578,12 @@ describe('IgxTabs', () => {
578578
expect(theTabs[2].nativeTabItem.nativeElement.classList.contains(tabItemSelectedCssClass)).toBe(true);
579579
});
580580

581-
it('should clear the selection indicator when not tab item is selected', fakeAsync(() => {
582-
fixture.ngZone.run(() => { router.initialNavigation(); });
583-
tick();
581+
it('should hide the selection indicator when no tab item is selected', () => {
584582
expect(tabsComp.selectedIndicator.nativeElement.style.visibility).toBe('visible');
585-
586-
fixture.ngZone.run(() => { router.navigate(['/']); });
587-
tick();
583+
theTabs[1].isSelected = false;
588584
fixture.detectChanges();
589585
expect(tabsComp.selectedIndicator.nativeElement.style.visibility).toBe('hidden');
590-
}));
586+
});
591587

592588
});
593589

0 commit comments

Comments
 (0)