Created
June 23, 2023 14:52
-
-
Save RaimonxDev/8f302fb8de8995019662593780526f63 to your computer and use it in GitHub Desktop.
Intersection Observer Directive
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- Root observer tendra todas las referencias que tengan childObserver --> | |
<div rootObserver (observeElements)="fn($event)"> | |
<div childObserve>Element 1</div> | |
<div childObserve>Element 2</div> | |
<div childObserve>Element 2</div> | |
</div> | |
2 | |
<!-- Observar solo en "element 2" --> | |
<div | |
<div>Element 1</div> | |
<div childObserve (isIntersecting)="fb($event)" >Element 2</div> | |
<div>Element 2</div> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
inject, | |
OnInit, | |
AfterViewInit, | |
OnDestroy, | |
ContentChildren, | |
QueryList, | |
Directive, | |
ElementRef, | |
EventEmitter, | |
Input, | |
Output | |
} from '@angular/core'; | |
@Directive( | |
{ | |
selector: '[childObserve]', | |
standalone: true | |
} | |
) | |
export class ChildObserverDirective implements OnInit, OnDestroy { | |
private elementRef = inject(ElementRef); | |
private _rootMargin = '0px'; | |
private _threshold = 0.1; | |
private _root!: ElementRef | null; | |
@Input() | |
set rootElement(root: ElementRef | null) { | |
this._root = root; | |
} | |
get rootElement(): ElementRef | null { | |
return this._root; | |
} | |
@Input() | |
set rootMargin(value: string) { | |
this._rootMargin = value; | |
} | |
get rootMargin(): string { | |
return this._rootMargin; | |
} | |
@Input() | |
set threshold(value: number) { | |
this._threshold = value; | |
} | |
get threshold(): number { | |
return this._threshold; | |
} | |
@Output() rawElement: EventEmitter<IntersectionObserverEntry> = new EventEmitter(); | |
@Output() isIntersecting: EventEmitter<boolean> = new EventEmitter(); | |
private observer!: IntersectionObserver | null; | |
ngOnInit(): void { | |
this.observer = new IntersectionObserver( | |
(entries) => { | |
this.rawElement.emit(entries[0]), | |
this.isIntersecting.emit(entries[0].isIntersecting); | |
}, | |
{ | |
root: this.rootElement ? this.rootElement.nativeElement : null, | |
rootMargin: this.rootMargin, | |
threshold: this.threshold, | |
} | |
); | |
this.observer.observe(this.elementRef.nativeElement); | |
} | |
ngOnDestroy(): void { | |
this.observer?.disconnect(); | |
} | |
} | |
@Directive( | |
{ | |
selector: '[rootObserver]', | |
standalone: true | |
} | |
) | |
export class RootObserverDirective implements AfterViewInit { | |
@ContentChildren(ChildObserverDirective, { descendants: true }) childObserver!: QueryList<ChildObserverDirective>; | |
@Output() observeElements: EventEmitter<IntersectionObserverEntry> = new EventEmitter() | |
ngAfterViewInit(): void { | |
this.childObserver.forEach((child) => { | |
child.rawElement.subscribe(el => { | |
if (el.isIntersecting) { | |
this.observeElement.emit(el); | |
} | |
}); | |
}); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment