Skip to content

Commit

Permalink
fix(tab-set): fix default tab with routing
Browse files Browse the repository at this point in the history
resolve several issues relating to setting the default tab based on url

closes #2061
  • Loading branch information
andrew-frueh committed Feb 28, 2023
1 parent 094552f commit cdc7161
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div class="tab-select-container">
<hc-form-field inline>
<hc-label>Tab Selected:</hc-label>
<hc-select [formControl]="tabSelected">
<hc-select [formControl]="tabSelected" (change)="controlChanged()">
<option value="0">First Tab</option>
<option value="1">Second Tab</option>
<option value="2">Third Tab</option>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,21 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { TabChangeEvent } from '@healthcatalyst/cashmere';
import { Subject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';

@Component({
selector: 'hc-selected-tab-input-example',
templateUrl: 'selected-tab-input-example.component.html',
// TODO: delete the SCSS file if you don't need it in the example
styleUrls: ['selected-tab-input-example.component.scss']
})
export class SelectedTabInputExampleComponent implements OnInit, OnDestroy {

export class SelectedTabInputExampleComponent {
tabSelected = new FormControl(1);
currentSelected = 1;
unsubscribe = new Subject<void>();
currentSelected = 2;

selectionChanged(event: TabChangeEvent): void {
this.tabSelected.setValue(event.index);
}

ngOnInit(): void {
this.tabSelected.valueChanges.pipe(
map(value => {
if (value) {
return Number(value);
}

return 0;
}),
takeUntil(this.unsubscribe)
).subscribe(value => {
this.currentSelected = value;
});
}

ngOnDestroy(): void {
this.unsubscribe.next();
this.unsubscribe.complete();
controlChanged(): void {
this.currentSelected = Number(this.tabSelected.value);
}
}
43 changes: 27 additions & 16 deletions projects/cashmere/src/lib/tabs/tab-set/tab-set.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {QueryList} from '@angular/core';
import {EventEmitter, TemplateRef} from '@angular/core';
import {TabComponent} from '../tab/tab.component';
import {ActivatedRoute, Router} from '@angular/router';
import {Subject, interval, fromEvent, BehaviorSubject, Subscription} from 'rxjs';
import {Subject, interval, fromEvent, Subscription} from 'rxjs';
import {distinctUntilChanged, filter, take, takeUntil} from 'rxjs/operators';
import {parseBooleanAttribute} from '../../util';
import {HcPopoverAnchorDirective} from '../../pop';
Expand Down Expand Up @@ -72,7 +72,7 @@ export class TabSetComponent implements AfterContentInit {
private _tabsTotalWidth = 0;
public _collapse = false;
public _moreList: Array<TabComponent> = [];
private _selectedTabSubject = new BehaviorSubject<number | TabComponent>(0);
private _selectedTabSubject = new Subject<number | TabComponent>();
private unsubscribe = new Subject<void>();

/** The content to be displayed for the currently selected tab.
Expand Down Expand Up @@ -117,7 +117,8 @@ export class TabSetComponent implements AfterContentInit {
}

/** Zero-based numerical value specifying which tab to select by default, setting to `none` means no tab
* will be immediately selected. Defaults to 0 (the first tab). */
* will be immediately selected. Defaults to 0 (the first tab).
* For tabs using routing, the default tab will be set by the url and use this value as a fallback if no tab routerLinks match the url. */
@Input()
get defaultTab(): string | number {
return this._defaultTab;
Expand Down Expand Up @@ -436,7 +437,8 @@ export class TabSetComponent implements AfterContentInit {
}
} else {
if ( this._routerEnabled ) {
this.router.navigate([activeTab.routerLink], {relativeTo: this.route});
const routeArray = Array.isArray(activeTab.routerLink) ? activeTab.routerLink : [activeTab.routerLink];
this.router.navigate(routeArray, {relativeTo: this.route, queryParams: activeTab.queryParams});
}
this._setActive(activeTab, shouldEmit, scrollIntoView);
}
Expand Down Expand Up @@ -476,7 +478,10 @@ export class TabSetComponent implements AfterContentInit {
// is triggered
const tabArray = this._tabs.toArray();
if (tabArray[Number(this.defaultTab)]) {
setTimeout(() => this._setActive(tabArray[Number(this.defaultTab)]));
setTimeout(() => {
this._selectedTab = tabArray[Number(this.defaultTab)];
this._setActive(tabArray[Number(this.defaultTab)]);
});
} else {
invalidDefaultTab(this.defaultTab);
}
Expand All @@ -499,22 +504,28 @@ export class TabSetComponent implements AfterContentInit {
}

private defaultToFirstRoute() {
const foundRoute = this._tabs
.map(tab => tab.routerLink)
.map(routerLink => this.mapRouterLinkToString(routerLink))
.find(routerLink => {
const currentRoute = this.router.url;
return currentRoute === routerLink || currentRoute.indexOf(`${routerLink}/`) > -1;
});
const tabArray = this._tabs.toArray();
let routeTab = -1;

for ( let i=0; i < tabArray.length; i++ ) {
const routerLink = this.mapRouterLinkToString(tabArray[i].routerLink);
const currentRoute = this.router.url.split("?")[0];
if( currentRoute === routerLink || currentRoute.indexOf(`${routerLink}/`) > -1 ) {
routeTab = i;
break;
}
}

if (foundRoute) {
if ( routeTab >= 0 ) {
this._selectedTab = tabArray[routeTab];
return;
}

const tabArray = this._tabs.toArray();
if (tabArray[Number(this.defaultTab)]) {
const firstRoute = this.mapRouterLinkToString(tabArray[Number(this.defaultTab)].routerLink);
this.router.navigate([firstRoute], {relativeTo: this.route});
const firstRouteLink = tabArray[Number(this.defaultTab)].routerLink;
const firstRouteArray = Array.isArray(firstRouteLink) ? firstRouteLink : [firstRouteLink];
this._selectedTab = tabArray[Number(this.defaultTab)];
this.router.navigate(firstRouteArray, {relativeTo: this.route, queryParams: tabArray[Number(this.defaultTab)].queryParams});
}
}

Expand Down
52 changes: 6 additions & 46 deletions scripts/search-prep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ function readFoundationsFiles() {

// Index the content section which is a combination of markdown and components
function readContentFiles() {
// Start by parsing the main content markdown files
glob('guides/content/*.md', function (er, files) {
// Start by parsing the markdown files
glob('{guides/content/*.md,guides/content/*/*.md}', function (er, files) {
files
.map(file => {
const basename = path.basename(file, path.extname(file));
Expand Down Expand Up @@ -240,13 +240,16 @@ function readContentFiles() {
const endOfLine = element.indexOf( '\n' );
sectionTitle = element.substr( 2, endOfLine - 2);
}
const pathParts = mapping.path.split('/');
pathParts.shift();
pathParts[pathParts.length - 1] = mapping.basename;
const sectionObj = object = ({
// Set id to the sectionTitle in snake case
id: changeCase.snakeCase(sectionTitle),
title: changeCase.titleCase(sectionTitle) + ' - ' + changeCase.titleCase(mapping.basename),
// Remove all the markdown from the file content and set it so we can search through it
content: mdGetContent(element),
link: 'content/' + mapping.basename,
link: pathParts.join('/'),
category: 'content',
// Set displayName to basename for display purposes
displayName: mapping.basename,
Expand All @@ -261,49 +264,6 @@ function readContentFiles() {
});
});

// Then parse the user persona markdown files
glob('guides/content/personas/*.md', function (er, files) {
files
.map(file => {
const basename = path.basename(file, path.extname(file));
return {
path: file,
basename: basename,
outFile: basename
};
})
.forEach(mapping => {
const fileContent = fs.readFileSync(mapping.path, 'utf8');
// Go through each file and find titles
let matches: RegExpExecArray | null;
let found: string[] = [];
while ((matches = guideTitleRegex.exec(fileContent)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (matches.index === guideTitleRegex.lastIndex) {
guideTitleRegex.lastIndex++;
}
matches.forEach((match: string, groupIndex: number) => {
if (groupIndex === 1) {
found.push(match);
}
});
}

const sectionObj = object = ({
id: changeCase.snakeCase(mapping.basename),
title: changeCase.titleCase(mapping.basename),
content: mdGetContent(fileContent),
link: 'content/personas/' + mapping.basename,
category: 'content',
displayName: mapping.basename,
type: 'persona',
section: changeCase.paramCase(mapping.basename)
});

searchArray.push(sectionObj);
});
});

// Then parse the content components
glob('src/app/content/*/*.html', function (er, files) {
files
Expand Down
2 changes: 1 addition & 1 deletion src/app/analytics/analytics.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</div>
<div class="hc-components-right-column">
<hc-tab-set class="full-height" [defaultTab]="queryTab">
<hc-tab *ngFor="let tab of selectOptions" [tabTitle]="tab.data.title" [routerLink]="'/analytics/' + tab.path">{{tab.data.title}}</hc-tab>
<hc-tab *ngFor="let tab of selectOptions" [tabTitle]="tab.data.title" [routerLink]="['/analytics',tab.path]">{{tab.data.title}}</hc-tab>
</hc-tab-set>
</div>
</div>
2 changes: 1 addition & 1 deletion src/app/content/content.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</div>
<div class="hc-components-right-column">
<hc-tab-set class="full-height" [defaultTab]="queryTab">
<hc-tab *ngFor="let tab of selectOptions" [tabTitle]="tab.data.title" [routerLink]="'/content/' + tab.path">{{tab.data.title}}</hc-tab>
<hc-tab *ngFor="let tab of selectOptions" [tabTitle]="tab.data.title" [routerLink]="['/content',tab.path]">{{tab.data.title}}</hc-tab>
</hc-tab-set>
</div>
</div>
2 changes: 1 addition & 1 deletion src/app/foundations/foundations.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</div>
<div class="hc-components-right-column">
<hc-tab-set class="full-height" [defaultTab]="queryTab">
<hc-tab *ngFor="let tab of selectOptions" [tabTitle]="tab.data.title" [routerLink]="'/foundations/' + tab.path">{{tab.data.title}}</hc-tab>
<hc-tab *ngFor="let tab of selectOptions" [tabTitle]="tab.data.title" [routerLink]="['/foundations',tab.path]">{{tab.data.title}}</hc-tab>
</hc-tab-set>
</div>
</div>

0 comments on commit cdc7161

Please sign in to comment.