You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've been playing with the ScrollSpy a little recently with implementation based on the IntersectionObserver. Here is the RFC for the API I came up with.
1. ScrollSpy service
It can be started/stopped on any element or on the whole document. You can add/remove fragments to watch and be notified when a particular fragment becomes active.
You can configure rootMargin for the IntersectionObserver and pass a ChangeDetectorRef that will be marked for check when active fragment changes.
It also allows to scroll to a particular fragment manually.
interfaceNgbScrollSpyOptionsextendsPick<IntersectionObserverInit,'rootMargin'>{changeDetectorRef?: ChangeDetectorRef;}
@Injectable({providedIn: 'root'})classNgbScrollSpyService{getactive(): string;// currently active fragmentgetactive$(): Observable<string>;// active fragmentstart(element: HTMLElement|Document,options: NgbScrollSpyOptions={});// starts intersection observerstop();// stops intersection observeraddFragment(id: string);// adds a new element to watch forremoveFragment(id: string);// removes the element from watchingscrollTo(id: string);// scrolls to a fragment}
Example 1 - Service usage
constscrollSpy=inject(NgbScrollSpyService);constchangeDetectorRef=inject(ChangeDetectorRef);// optional of coursescrollSpy.start(document,{rootMargin: '24px', changeDetectorRef });scrollSpy.addFragment('one');scrollSpy.active;// 'one' or ''scrollSpy.active$.subscribe(active=>{});scrollSpy.addFragment('two');scrollSpy.scrollTo('two');
2. ScrollSpy directive
Allows to setup the NgbScrollSpy service on a particular element.
NgbScrollSpyItem and NgbScrollSpyNav allow to handle .active class changes and build hierarchical menus.
@Directive({selector: '[ngbScrollSpyItem]',exportAs: 'ngbScrollSpyItem'})classNgbScrollSpyItem{
@Input('ngbScrollSpyItem')scrollSpy: NgbScrollSpy;// optional scrollspy
@Input()fragment: string;// references a fragment to scroll to
@Input()parent: string;// references a parent item in case of hierarchical highlightingisActive(): boolean;// `true`, if current item is activescrollTo();// scrolls to a current item}
@Directive({selector: '[ngbScrollSpyNav]'})classNgbScrollSpyNav{
@Input('ngbScrollNav')scrollSpy: NgbScrollSpy;// optional scrollspy}
Example 3.1 - Simple menu items
These will handle click and scrolling.
<buttonngbScrollSpyItemfragment="one">One</button><!-- service instance got via DI --><button[ngbScrollSpyItem]="s" fragment="one">One</button><!-- scrollSpy referenced directly --><button[ngbScrollSpyItem]="[s, 'one']">One</button><!-- shortcut syntax --><divngbScrollSpy#s="ngbScrollSpy"><h2ngbScrollSpyFragment="one"></h2></div>
Example 3.2 - Simple menu links
These will not handle clicks and won't scroll, usually this will be done by the router.
<angbScrollSpyItemrouterLink="." fragment="one">One</a><!-- service instance got via DI --><a[ngbScrollSpyItem]="s" fragment="one">One</a><!-- scrollSpy referenced directly --><divngbScrollSpy#s="ngbScrollSpy"><h2ngbScrollSpyFragment="one"></h2></div>
Example 3.3 - Using items
Any individual item can be referenced
<buttonngbScrollSpyItem#item="ngbScrollSpyItem" fragment="one">One</button><button(click)="item.scrollTo()">Scroll to</button><span[class.active]="item.isActive()">First is active</span>
Example 3.4 - Complex menus
These will allow to build hierarchical highlighting. Can be applied to an arbitrary markup and bound either to a service via DI or to a particular instance of a ScrollSpy directive.
In this case parent-child relationships have to be esablished manually via the parent link and ngbScrollSpyNav group.
<nav[ngbScrollSpyNav]="s"><!-- can also get an instance via DI --><navclass="nav nav-pills flex-column"><aclass="nav-link" [ngbScrollSpyItem]="s" fragment="p1"> Parent 1</a><navclass="nav nav-pills flex-column"><aclass="nav-link ms-3 my-1" ngbScrollSpyItemfragment="one" parent="p1">Item 1</a><aclass="nav-link ms-3 my-1" [ngbScrollSpyItem]="[s, 'two', 'p1']">Item 2</a></nav></nav></nav><divngbScrollSpy#s="ngbScrollSpy"><h1ngbScrollSpyFragment="p1"></h1><h2ngbScrollSpyFragment="one"></h2><h2ngbScrollSpyFragment="two"></h2></div>
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Hey,
I've been playing with the ScrollSpy a little recently with implementation based on the
IntersectionObserver
. Here is the RFC for the API I came up with.1. ScrollSpy service
It can be started/stopped on any element or on the whole document. You can add/remove fragments to watch and be notified when a particular fragment becomes active.
You can configure
rootMargin
for theIntersectionObserver
and pass aChangeDetectorRef
that will be marked for check when active fragment changes.It also allows to scroll to a particular fragment manually.
Example 1 - Service usage
2. ScrollSpy directive
Allows to setup the
NgbScrollSpy
service on a particular element.Example 2 - Directive usage
3. Helper menu directives
NgbScrollSpyItem
andNgbScrollSpyNav
allow to handle.active
class changes and build hierarchical menus.Example 3.1 - Simple menu items
These will handle click and scrolling.
Example 3.2 - Simple menu links
These will not handle clicks and won't scroll, usually this will be done by the router.
Example 3.3 - Using items
Any individual item can be referenced
Example 3.4 - Complex menus
These will allow to build hierarchical highlighting. Can be applied to an arbitrary markup and bound either to a service via DI or to a particular instance of a ScrollSpy directive.
In this case parent-child relationships have to be esablished manually via the
parent
link andngbScrollSpyNav
group.cc @jnizet, @ExFlo, @divdavem, @fbasso
Beta Was this translation helpful? Give feedback.
All reactions