Follow below steps to override OOB Spartacus footer component:
1. Create custom footer component typescript file(TestFooterNavigationComponent). copy the content/code from OOB FooterNavigationComponent file and paste it in custom component
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { CmsNavigationComponent } from '@spartacus/core';
import { CmsComponentData, NavigationNode } from '@spartacus/storefront';
import { Observable } from 'rxjs/internal/Observable';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-bdifooter-navigation',
templateUrl: './bdifooter-navigation.component.html',
changeDetection:ChangeDetectionStrategy.OnPush
})
export class TestFooterNavigationComponent {
//using it to display current year for footer copyright text
today: number = Date.now();
node$: Observable<NavigationNode> = this.service.getNavigationNode(
this.componentData.data$
);
styleClass$: Observable<string> = this.componentData.data$.pipe(
map((d) => d?.styleClass)
);
constructor(
protected componentData: CmsComponentData<CmsNavigationComponent>,
protected service: NavigationService
) {}
}
2. Create custom footer component HTML file. Copy the content of OOB footer component HTML located at:
C:\spartacus\spartacus-schematics-2.1.1\projects\storefrontlib\src\cms-components\navigation\footer-navigation\footer-navigation.component.html
and modify the selector based on custom UI component
<!-- custom UI component which is used to display footer UI. We you can refer it in
next steps below-->
<!-- component to display custom UI/modified UI -->
<app-testfooter-navigation-ui
[node]="node$ | async"
[ngClass]="styleClass$ | async"
[iscollapsible]="true"
[isOpen]="true"
></app-testfooter-navigation-ui>
<!-- footer Copy right Text -->
<ng-container >
<div class="cx-notice">
© {{ 'testFooter.copyright.beforedate' | cxTranslate | uppercase }}
{{ today | cxDate: 'yyyy' }}
{{ 'bdiFooter.copyright.afterdate' | cxTranslate | uppercase }}
</div>
</ng-container>
3. Create footer navigation Module typescript file and use configModule.withConfig to override OOB FooterNavigationComponent(highlighted in Green below) with Custom component TestFooterNavigationComponent
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ConfigModule, I18nModule, UrlModule } from '@spartacus/core';
import { FooterNavigationModule, GenericLinkModule, IconModule, LinkModule, MediaModule, NavigationModule } from '@spartacus/storefront';
import { BDIFooterNavigationUIComponent } from './bdifooter-navigation-ui.component';
import { BDIFooterNavigationComponent } from './bdifooter-navigation.component';
import { BDISocialMediaNavigationUIComponent } from './bdisocialmedia-navigation-ui.component';
import { BDISocialMediaNavigationComponent } from './bdisocialmedia-navigation.component';
@NgModule({
declarations: [TestFooterNavigationComponent,TestFooterNavigationUIComponent],
imports: [
CommonModule,
NavigationModule,
FooterNavigationModule,
IconModule,
LinkModule,
GenericLinkModule,
UrlModule,
I18nModule,
MediaModule,
ConfigModule.withConfig({
cmsComponents: {
FooterNavigationComponent:{
component:TestFooterNavigationComponent // this is custom component
},
}
})
],
exports: [TestFooterNavigationComponent,TestFooterNavigationUIComponent],
})
export class TestFooterNavigationModule { }
4. Include module in app.module.ts file
@NgModule({
declarations: [AppComponent, POReportFormComponent, MockloginComponent],
imports: [
BrowserModule,
AppRoutingModule,
LoginModule,
ReactiveFormsModule,
RouterModule,
UrlModule,
I18nModule,
SpinnerModule,
FormErrorsModule,
DateTimePickerModule,
TestFooterNavigationModule,
B2cStorefrontModule.withConfig({
backend: {
occ: {
baseUrl: 'https://localhost:9002',
prefix: '/rest/v2/',
5. Create UI component and copy the content from OOB UI component located at :
C:\spartacus\spartacus-schematics-2.1.1\projects\storefrontlib\src\cms-components\navigation\navigation\navigation-ui.component.ts
and modified as shown below. remove unnecessary code and keep the one which is required.
import { ChangeDetectionStrategy, Component, HostBinding, Input, OnDestroy, Renderer2 } from '@angular/core';
import { NavigationNode } from '@spartacus/storefront';
@Component({
selector :'app-bdifooter-navigation-ui',
templateUrl:'./bdifooter-navigation-ui.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TestFooterNavigationUIComponent implements OnDestroy {
@Input() node: NavigationNode;
@Input() @HostBinding('class.is-open') isOpen = true;
@Input() @HostBinding('class.isCollapse') iscollapsible= true;
private openNodes: HTMLElement[] = [];
constructor( private renderer: Renderer2 ) { }
// function which hadles collpsible behaviour in mobile device
toggleOpen(event: UIEvent): void {
if (event.type === 'keydown') {
event.preventDefault();
}
const node = <HTMLElement>event.currentTarget;
if (this.openNodes.includes(node)) {
this.openNodes = this.openNodes.filter((n) => n !== node);
this.renderer.removeClass(node, 'is-open');
} else {
this.renderer.addClass(node, 'is-open');
this.openNodes.push(node);
}
this.updateClasses(node)
event.stopImmediatePropagation();
event.stopPropagation();
}
private updateClasses(currentNode:HTMLElement): void {
this.openNodes.forEach((node)=>{
if(node !== currentNode){
this.renderer.removeClass(node, 'is-open');
}
} );
this.openNodes = this.openNodes.filter((n)=> n == currentNode)
}
ngOnDestroy() {
this.openNodes = [];
}
}
6. create HTML for UI component. copy and paste the content from OOB UI component located at :
C:\spartacus\spartacus-schematics-2.1.1\projects\storefrontlib\src\cms-components\navigation\navigation\navigation-ui.component.html
and modify it based on your requirement
<ng-container *ngFor="let child of node?.children">
<ng-container *ngTemplateOutlet="nav; context: { node: child, depth: 0 }">
</ng-container>
</ng-container>
<!-- we generate links in a recursive manner -->
<ng-template #nav let-node="node" let-depth="depth">
<nav (click)="toggleOpen($event)" >
<cx-generic-link
*ngIf="
node.url && (!node.children || node.children?.length === 0);
else heading
"
[url]="node.url"
[target]="node.target"
[style]="node.styleAttributes"
[class]="node.styleClasses"
>
{{ node.title }}
</cx-generic-link>
<ng-template #heading>
<h5 [attr.aria-label]="node.title" >
{{ node.title }}
</h5>
</ng-template>
<!-- we add a wrapper to allow for better layout handling in CSS -->
<div class="wrapper" *ngIf="node.children?.length > 0">
<cx-generic-link
*ngIf="node.url"
[url]="node.url"
[target]="node.target"
class="all"
>
{{ 'navigation.shopAll' | cxTranslate: { navNode: node.title } }}
</cx-generic-link>
<div class="childs" >
<ng-container *ngFor="let child of node.children">
<ng-container
*ngTemplateOutlet="nav; context: { node: child }"
>
</ng-container>
</ng-container>
</div>
</div>
</nav>
</ng-template>
7. Create SCSS file for you custom component or extend the OOB one
for footer navigation component:
app-testfooter-navigation {
a {
font-size: var(--cx-font-small, 0.8rem);
&:hover {
color: var(--cx-color-inverse);
text-decoration: underline;
}
}
}
for footer Navigation UI component:
%testfooter-nav-wrapper {
.wrapper {
cursor: default;
}
// create width of wrapper
.wrapper[attr='1'] {
width: 200px;
}
.wrapper[attr='2'] {
width: 400px;
}
&.isCollapse {
.wrapper {
@include media-breakpoint-down(xs) {
height: 0;
overflow: hidden;
}
//color: #000;
}
}
}
%testfooter-nav-heading {
nav {
&:focus {
color: var(--cx-g-color-primary);
}
}
h5 {
margin: 0;
}
&.isCollapse {
h5,
cx-generic-link {
display: flex;
align-items: center;
white-space: nowrap;
color: currentColor;
@include media-breakpoint-down(xs) {
&:hover {
color: var(--cx-color-primary);
}
&:focus {
z-index: 1;
position: relative;
}
}
a {
display: block;
width: 100%;
&:focus {
z-index: 1;
position: relative;
}
}
}
@include media-breakpoint-down(xs) {
// make all first level hedings uppercase in mobile view
> nav {
> h5,
> cx-generic-link {
text-transform: uppercase;
font-weight: 600;
}
}
h5 {
border-bottom: 1px solid var(--cx-color-light);
display: flex;
justify-content: space-between;
cursor: pointer;
}
h5,
cx-generic-link a {
padding: 1rem;
}
}
@include media-breakpoint-up(lg) {
> nav {
cursor: pointer;
// top level headings
> h5 {
margin-top: 3px;
padding: 20px 15px 10px 0;
}
// first level headings will be bold in desktop
nav > h5 {
@include type('5');
cursor: default;
&:hover {
color: currentColor;
}
}
}
}
}
cx-generic-link.all {
text-decoration: underline;
}
}
@include media-breakpoint-up(lg) {
cx-navigation-ui > nav > cx-generic-link > a {
padding: 20px 15px 22px 0;
}
nav > div > cx-generic-link {
padding: 10px 0;
}
div.childs > nav > cx-generic-link > a {
padding: 5px 0;
}
}
%bdifooter-nav-links {
a {
color: currentColor;
}
}
app-testfooter-navigation-ui {
display: flex;
@extend %testfooter-nav-heading;
@extend %testfooter-nav-wrapper;
@extend %testfooter-nav-links;
nav {
outline: none;
}
// first level heading / links
h5 {
text-transform: uppercase;
@include type('5');
margin-bottom: 20px;
}
justify-content: center;
@include media-breakpoint-down(sm) {
flex-direction: column;
}
> nav {
margin: 3vw;
}
&.isCollapse {
@include media-breakpoint-down(xs) {
> nav {
display: block;
cx-generic-link.all {
display: none;
}
}
&.is-open {
nav.is-open {
display: initial;
cx-generic-link.all {
display: initial;
}
> .wrapper {
height: auto;
}
}
}
}
}
}
8. Save all changes and run ng serve command to test your changes.
Good Luck.
=========================================================================
Comments
Post a Comment