I am trying to make a Snap-to-Component Directive. At this point I have made a proof of concept with logic that lives in the app component (which would possibly be replaced with Renderer2 HostListeners and HostBindings) and it looks like I would have to get the dom properties (child1L, child1R...etc.) of the children probably using Renderer2. My question is how would you decouple what I have done so far into a directive or a group of parent and child directives? Or at least what direction would you go from here? I am new to using Renderer2, HostListeners, and HostBinding so I was wondering how a more experienced person would do this. Thank you. Here is my current stackblitz.
app.component.ts:
import { Component,ElementRef,ViewChild } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
switchDirection = "first";
head: ElementRef;
@ViewChild('child01') child01;
@ViewChild('child02') child02;
@ViewChild('child03') child03;
onScroll(event: Event) {
let viewBoundaryL = (event.target as HTMLElement).scrollLeft;
console.log("viewBoundaryL:" + viewBoundaryL);
//SNAP FROM FIRST TO SECOND CHILD
if(viewBoundaryL >= 50 && this.switchDirection === "first"){
this.child02.el.nativeElement.scrollIntoView({ behavior: 'smooth', block: "center" });
setTimeout(() => {
this.switchDirection = "second";
// console.log(this.switchDirection)
}, 300);
}
//SNAP FROM SECOND TO FIRST CHILD
if(viewBoundaryL <= 310 && this.switchDirection === "second"){
this.child01.el.nativeElement.scrollIntoView({ behavior: 'smooth', block: "center" });
setTimeout(() => {
this.switchDirection = "first";
// console.log(this.switchDirection)
}, 300);
}
//SNAP FROM SECOND TO THIRD CHILD
if(viewBoundaryL >= 370 && this.switchDirection === "second"){
this.child03.el.nativeElement.scrollIntoView({ behavior: 'smooth', block: "center" });
setTimeout(() => {
this.switchDirection = "third";
// console.log(this.switchDirection)
}, 300);
}
//SNAP FROM THIRD TO SECOND CHILD
if(viewBoundaryL <= 615 && this.switchDirection === "third"){
this.child02.el.nativeElement.scrollIntoView({ behavior: 'smooth', block: "center" });
setTimeout(() => {
this.switchDirection = "second";
// console.log(this.switchDirection)
}, 300);
}
}
}
app.component.html:
<div class="container" (scroll)="onScroll($event)" >
<child1 #child01></child1>
<child2 #child02></child2>
<child3 #child03></child3>
</div>
Thanks for your insights!
You probably want to create an attribute directive.
You can easily create a directive by using the Angular CLI with the following command (you can provide a path as the name core/directives/my-directive-name):
ng generate directive <name-of-directive>
Then in the constructor you can add the following to get reference to the element.
el: ElementRef
Finally using a HostListener, or any technique to bind to the scroll event. You can place a call to your snap to element code (will have to change to just check for itself), the element then will check if itself needs to initiate the scroll. And if it meets the condition, then it does.
For further bonus points, you can add inputs for setting and when to snap to the element for example, you template with the directive will look like this:
<div [myDirective] [scrollAt]="300"></div>
And then in the directive itself you would have:
@Input() scrollAt: number = 300 // sets a default incase it isn't provided;
Then you can use this variable for your view boundary.
Hope this helps, or at least puts you on the right track!