Creating a directive that allows you to vertically scroll to an element
Can you imagine being able to instantly jump to any place that your eyes can see? That would be awesome! Wouldn’t it? But what if we wanted our app to be able to do that? In this recipe, you’ll create a directive that the user can click to jump to specific sessions in an Angular application.
Getting ready
The app that we are going to work with resides in start/apps/chapter02/ng-scroll-to-directive inside the cloned repository:
- Open the code repository in your code editor.
- Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
npm run serve ng-scroll-to-directiveThis should open the app in a new browser tab, and you should see the following:

Figure 2.6: ng-scroll-to-directive app running on http://localhost:4200
How to do it…
- First, we’ll create a
scroll-todirective so that we can enhance our application with smooth scrolls to different sections. We’ll do this using the following command in the workspace root folder:cd start && nx g directive scroll-to --directory apps/chapter02/ng-scroll-to-directive/src/app/directivesIf asked, choose the
@nx/angular:component schematicsand choose the “As provided” action.
- Now, we need to make the directive capable of accepting an
@Input()that’ll contain the CSS Query Selector for our target section, which we’ll scroll to upon the element’sclickevent. Let’s add the input as follows to ourscroll-to.directive.tsfile:import { Directive, Input } from '@angular/core'; @Directive({ selector: '[appScrollTo]' }) export class ScrollToDirective { @Input() target = ''; } - Now, we’ll apply the
appScrollTodirective to the links in theapp.component.htmlfile along with the respective targets. We’ll replace thehrefattribute with thetargetattribute. The code should look like this:... <main class="content" role="main"> <div class="page-links"> <h4 class="page-links__heading"> Links </h4> <a class="page-links__link" appScrollTotarget= "#resources">Resources</a> <a class="page-links__link" appScrollTotarget= "#nextSteps">Next Steps</a> <a class="page-links__link" appScrollTotarget= "#moreContent">More Content</a> <a class="page-links__link" appScrollTotarget= "#furtherContent">Further Content</a> <a class="page-links__link" appScrollTotarget= "#moreToRead">More To Read</a> </div> </main> ... <a appScrollTo target="#toolbar" class="to-top-button w-12 h-12 text-white flex items-center justify-center"> <span class="material-symbols-outlined text-3xl text- white"> expand_less </span> </a> - Now, we’ll implement the
HostListener()decorator to bind theclickevent to the element the directive is attached to. We’ll just log thetargetinput when we click the links. Let’s implement this, and then you can try clicking on the links to see the value of thetargetinput on the console:import { Directive, Input, HostListener } from '@angular/core'; @Directive({ selector: '[appScrollTo]' }) export class ScrollToDirective { @Input() target = ''; @HostListener('click') onClick() { console.log(this.target); } ... } - We will now implement the logic to scroll to a particular target. We’ll use the
document.querySelectormethod, using thetargetvariable’s value to get the element, and then theElement.scrollIntoViewweb API to scroll to the target element. With this change, you should see the page scrolling to the target element already when you click the corresponding link:... export class ScrollToDirective { @Input() target = ''; @HostListener('click') onClick() { const targetElement = document.querySelector(this.target); if (!targetElement) { throw new Error('`target' is required.`); } targetElement.scrollIntoView(); } ... } - All right—we got the scroll to work. “But what’s new, Ahsan? Isn’t this exactly what we were already doing with the href implementation before?” Well, you’re right. But we’re going to make the scroll super smoooooth. We’ll pass
scrollIntoViewOptionsas an argument to thescrollIntoViewmethod with the{behavior: "smooth"}value to use an animation during the scroll. The code should look like this:... export class ScrollToDirective { @Input() target = ''; @HostListener('click') onClick() { const targetElement = document.querySelector (this.target); targetElement.scrollIntoView({behavior: 'smooth'}); } }
How it works…
The essence of this recipe is the web API that we’re using within an Angular directive, which is Element.scrollIntoView. We first attach our appScrollTo directive to the elements that should trigger scrolling upon clicking them. We also specify which element to scroll to by using the target input for each directive attached. Then, we implement the click handler inside the directive with the scrollIntoView method to scroll to a particular target, and to use a smooth animation while scrolling, we pass the {behavior: 'smooth'} object as an argument to the scrollIntoView method.
See also
scrollIntoViewmethod documentation: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView- Angular attribute directives documentation: https://angular.io/guide/testing-attribute-directives