File
Implements
Metadata
selector |
div[tab-main] |
styleUrls |
./tab-main.component.scss |
templateUrl |
./tab-main.component.html |
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Methods
ngOnDestroy
|
ngOnDestroy()
|
|
|
parseJson
|
parseJson(jsonData: any)
|
|
Parameters :
Name |
Type |
Optional |
jsonData |
any
|
No
|
|
parseTab
|
parseTab(rawTabJson: any)
|
|
Parameters :
Name |
Type |
Optional |
rawTabJson |
any
|
No
|
|
id
|
Type : string
|
Default value : this.idService.getId()
|
|
import { Component, OnInit, Input, OnDestroy, HostBinding } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { RowResolverService } from 'src/app/core/services/row-resolver.service';
import { UtilService } from 'src/app/core/services/util-service/util.service';
import { ConstantsService } from 'src/app/shared/constants/constants.service';
import { IdGeneratorService } from 'src/app/core/services/id-generator.service';
import { ResizeContentService } from 'src/app/core/services/resize-service/resize-content.service';
interface Tab {
Id: string; // Used by the shortcuts component as a scroll target
Title: string;
Content: any[];
ContentIds: string[];
}
interface TabRow {
activeTab: Tab;
activeIndex: number;
tabs: Tab[];
tabIdToActivate: string;
}
@Component({
selector: 'div[tab-main]',
templateUrl: './tab-main.component.html',
styleUrls: ['./tab-main.component.scss'],
})
export class TabMainComponent implements OnInit, OnDestroy {
@Input() entity;
data: TabRow;
id: string = this.idService.getId();
inDesktop: boolean;
constructor(public rowResolver: RowResolverService,
// Constants is used in the html template
public constants: ConstantsService,
public idService: IdGeneratorService,
public util: UtilService,
private activatedRoute: ActivatedRoute,
public resize: ResizeContentService) { }
ngOnInit() {
this.data = this.parseJson(this.entity);
this.resize.registerCallback(this.id, e => this.onResize());
// Call it here so that the inDesktop get's its proper value without the need to resize the browser
this.onResize();
}
ngOnDestroy(): void {
this.resize.destroyCallback(this.id);
}
onResize() {
const currentWidth = window.innerWidth;
this.inDesktop = currentWidth >= this.constants.BOOTSTRAP_BREAKPOINTS.MD;
}
parseJson(jsonData: any): TabRow {
const itemId = (this.activatedRoute.snapshot.fragment || '');
const allRawTabs: any[] = this.util.extract(jsonData, 'Entities' ) || [];
const tabs = allRawTabs.map(rawTab => this.parseTab(rawTab));
const tab = // try find a tab with the tab nested component-id or tab id specified in the url
tabs.find(t => t.Id.includes(itemId)) ||
tabs.find(t => t.ContentIds.includes(itemId));
const tabIdToActivate = tab !== undefined ? tab.Id : '';
const tabRow: TabRow = {
activeTab: tabs[0],
activeIndex: 0,
tabs: tabs,
tabIdToActivate: tabIdToActivate
};
return tabRow;
}
parseTab(rawTabJson: any): Tab {
const tabTitle: string = this.util.extract(rawTabJson, 'TabTitle');
// Apply to row transformer since the template expects this format (this is the same that is used for regions)
const entities = this.util.extract(rawTabJson, 'TabContnetEntities');
const entitiesGroupedAsRows = this.rowResolver.transform(entities, 'MAIN');
const id = this.util.extract(rawTabJson, 'Id');
// Add ids for all entities present in all tabs
const contentIds: string[] = entities.map(e => {
if(e.Id !== undefined){
return e.Id.includes('-') ? `${this.constants.COMPONENT_ID_PREFIX}-${e.Id.split('-')[0]}` : `${this.constants.COMPONENT_ID_PREFIX}-${e.Id}`;
}
});
// Entities that don't have Id are arrays and need further processing
entities.forEach(e => {
if(e.Id === undefined && e.Entities !== undefined){
contentIds.push(e.Entities.map(ee => {
if(ee.Id !== undefined){
return ee.Id.includes('-') ? `${this.constants.COMPONENT_ID_PREFIX}-${ee.Id.split('-')[0]}` : `${this.constants.COMPONENT_ID_PREFIX}-${ee.Id}`;
}
}));
}
});
const tab: Tab = {
Id: `${this.constants.COMPONENT_ID_PREFIX}-${id}`,
Title: tabTitle,
Content: entitiesGroupedAsRows,
ContentIds: contentIds
};
return tab;
}
setActiveTab(tabRow: TabRow, index: number): void {
const newActive = tabRow.tabs[index];
tabRow.activeIndex = index;
tabRow.activeTab = newActive;
}
tabClick(index): void {
this.setActiveTab(this.data, index);
}
}
<!-- Desktop -->
<ngb-tabset class="tab-desktop" justify="start" *ngIf="inDesktop" [activeId]="data.tabIdToActivate">
<ngb-tab [id]="tab.Id" [title]="tab.Title" *ngFor="let tab of data.tabs">
<ng-template ngbTabContent>
<ng-container *ngFor="let row of tab?.Content">
<div dxa-entity [entities]="row" [region]="'MAIN'"></div>
</ng-container>
</ng-template>
</ngb-tab>
</ngb-tabset>
<!-- Mobile -->
<div class="tab-mobile">
<div ngbDropdown *ngIf="!inDesktop">
<div ngbDropdownToggle [id]="'dropdown-' + id">
<span>{{data?.activeTab.Title}}</span>
<i class="icon-chevronDown"> </i>
<i class="icon-chevronUp"> </i>
</div>
<div ngbDropdownMenu [attr.aria-labelledby]="'dropdown-' + id">
<div class="menu-item" [id]="tab.Id" [ngClass]="{'active-menu-item': i === data.activeIndex}" (click)="tabClick(i)" ngbDropdownItem *ngFor="let tab of data.tabs; let i = index">
<div class="container">
{{tab.Title}}
</div>
</div>
</div>
</div>
<div class="tab-content" *ngIf="!inDesktop">
<ng-container *ngFor="let row of data?.activeTab?.Content">
<div dxa-entity [entities]="row" [region]="'MAIN'"></div>
</ng-container>
</div>
</div>
@import "src/app/styles/helpers";
:host {
@include media-breakpoint-up(md) {
background-color: $light-green;
}
}
// Desktop
::ng-deep .tab-desktop {
.nav {
background-color: $light-green;
color: $cool-grey;
border: none;
display: flex;
@include make-container();
@include make-container-max-widths();
&-link {
padding: calc-rem(20) calc-rem(50);
@include font-scale(14, uppercase);
letter-spacing: calc-rem(0.4);
}
&-item {
text-align: center;
.nav-link.active {
border-color: $light-green;
// TODO Find a better solution for checking the background color
::ng-deep .support-page & {
background-color: $light-slate;
}
}
.nav-link {
text-transform: uppercase;
border: none;
border-top: calc-rem(2) solid $light-green;
&:hover {
border-color: $light-green;
}
}
a {
color: $cool-grey;
border: none;
}
}
}
}
::ng-deep .tab-content {
background-color: white;
}
// Mobile
.tab-mobile {
::ng-deep .dropdown {
display: flex;
min-height: calc-rem(75);
background-color: $light-green;
@include font-scale(14, uppercase);
letter-spacing: calc-rem(0.4);
cursor: pointer;
&-toggle {
@include make-container();
@include make-container-max-widths();
display: flex;
justify-content: space-between;
align-self: stretch;
align-items: center;
text-transform: uppercase;
&[aria-expanded=true] .icon-chevronDown {
display: none;
}
&[aria-expanded=false] .icon-chevronUp {
display: none;
}
&::after {
content: none;
}
i {
margin-right: calc-rem(10);
}
}
&-menu {
border: 1px solid $light-green;
background-color: $light-green;
width: 100%;
left: 0 !important;
padding: 0;
.menu-item {
cursor: pointer;
padding: calc-rem(15) 0;
background-color: $light-green;
@include font-scale(14, uppercase);
letter-spacing: calc-rem(0.4);
&:hover {
background-color: $white;
}
&.active-menu-item {
font-weight: bold;
}
}
}
}
}
Legend
Html element with directive