Issue
I am using ng-bootstrap [ngbScrollSpy]
directive in my project, as mentioned in the documentation, but it didn't work - on scroll the active item doesn't change.
My code is the following:
<div>
<div class="sticky-top">
<ul class="nav menu-sidebar">
<li >
<a [ngbScrollSpyItem]="[spy, 'about']">About</a>
</li>
<li >
<a [ngbScrollSpyItem]="spy" fragment="schedule">Schedule</a>
</li>
<li >
<a [ngbScrollSpyItem]="spy" fragment="hotel">Information about the hotel</a>
</li>
</ul>
</div>
<div ngbScrollSpy #spy="ngbScrollSpy" >
<section ngbScrollSpyFragment="about">
<h3>About</h3>
<p>{{some long long text and content}}</p>
</section>
<section ngbScrollSpyFragment="schedule">
<h3>Schedule</h3>
<p>{{some long long text and content}}</p>
</section>
<section ngbScrollSpyFragment="hotel">
<h3>Information about the hotel</h3>
<p>{{some long long text and content}}</p>
</section>
</div>
</div>
I saw in this stackoverflow question that my problem is that I didn't provide height
to my div, and that's true.
but my scroll spy sections spread through the whole page, not a small div, (the nav itself is sticky-top
). so I cannot give it height.
I understood that there is alternative way - to refresh the scrollspy on window scroll, but I don't find correct code that may help me.
can you solve my problem? provide me code for refreshing the scrollspy / give me tips about the height / help me to find another corresponding element.
thanks a lot!
attaching link to stackblitz demo
Solution
Since it seemed to be no solution for my demands, I decided to create my own scrollspy element via two directives:
scrollTo
directive will be responsible for scrolling to the section on pressing theli
link
import { Directive, HostListener, Input } from '@angular/core';
@Directive({
selector: '[scrollTo]'
})
export class ScrollToDirective {
@Input() target = '';
constructor() { }
@HostListener('click')
onClick() {
const targetElement = document.querySelector(this.target);
if(targetElement)
targetElement.scrollIntoView({block: 'start',behavior: 'smooth', inline:'nearest'});
}
}
scrolledTo
directive will be responsible for detecting when scrolling to current element
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[scrolledTo]',
exportAs: 'scrolledTo'
})
export class ScrolledToDirective {
@Input() isLast:boolean = false;
focus = false;
constructor(public el: ElementRef) { }
@HostListener('window:scroll', ['$event'])
onWindowScroll() {
const elementPosition = this.el.nativeElement.offsetTop;
const elementHeight = this.el.nativeElement.clientHeight;
//you can change the check according to your requirements
const scrollPosition = window.pageYOffset - window.screen.height / 2 ;
this.focus = scrollPosition >= elementPosition && scrollPosition <= elementPosition + elementHeight;
if(this.isLast)
this.focus = scrollPosition >= elementPosition;
}
}
and the html will be the following
<div>
<div class="sticky-top">
<ul class="nav menu-sidebar">
<li >
<a scrollTo target="#about" [class.active]="scrolledToElement1.focus">About</a>
</li>
<li >
<a scrollTo target="#schedule" [class.active]="scrolledToElement2.focus">Schedule</a>
</li>
<li >
<a scrollTo target="#hotel" [class.active]="scrolledToElement3.focus">Information about the hotel</a>
</li>
</ul>
</div>
<div >
<section scrolledTo #scrolledToElement1="scrolledTo" id="about">
<h3>About</h3>
<p>{{some long long text and content}}</p>
</section>
<section scrolledTo #scrolledToElement2="scrolledTo" id="schedule">
<h3>Schedule</h3>
<p>{{some long long text and content}}</p>
</section>
<section scrolledTo #scrolledToElement3="scrolledTo" id="hotel">
<h3>Information about the hotel</h3>
<p>{{some long long text and content}}</p>
</section>
</div>
</div>
credits:
Answered By - ayala
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.