Skip to content

Commit

Permalink
feat(sticky): adds ability to change scroll container
Browse files Browse the repository at this point in the history
re #25
  • Loading branch information
Can Kattwinkel committed Mar 4, 2019
1 parent 8cc121f commit 78c315d
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 11 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ export class SomeModule { }
</div>
```

#### Scroll in

Per default Sticky Things expects your body to be the element that scrolls. However, if Sticky Things is used in an `overflow`-container, that container must be made known to the directive.

This is best done with a query selector. If a string is provided it will be called with `document.querySelector`. Instead an HTML element (nativeElement) can be provided as well.

```html
<div class="scroll-container">
<div #spacer></div>
<div [spacer]="spacer" stickyThing="" [scrollContainer]="'.scroll-container'">
Scroll by!
</div>
</div>
```


#### Boundary Elements

Expand Down
6 changes: 4 additions & 2 deletions e2e/src/posa.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ describe('with position:absolute container', () => {


it('should recognize sticky ', async () => {
page.navigateToDev();
await browser.executeScript('window.scrollTo(0,501);');
await page.navigateToDev();

// dont use window scroll here.
browser.actions().mouseMove(await page.getOtherScrollable()).perform();
const hasStickyClass = await hasClass(page.getStickyElement(), 'is-sticky');
expect(hasStickyClass).toBe(true);
});
Expand Down
4 changes: 4 additions & 0 deletions e2e/src/posa.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export class PosaPage {
return element(by.css('.some-thing-sticky'));
}

getOtherScrollable() {
return element(by.css('.another-scrollable-container'));
}

getEnableButton() {
return element(by.css('#enable-btn'));
}
Expand Down
45 changes: 38 additions & 7 deletions projects/angular-sticky-things/src/lib/sticky-thing.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export class StickyThingDirective implements OnInit, AfterViewInit, OnDestroy {
marginBottom$ = new BehaviorSubject(0);
enable$ = new BehaviorSubject(true);

@Input() scrollContainer: string | HTMLElement;

@Input() set marginTop(value: number) {
this.marginTop$.next(value);
}
Expand All @@ -61,7 +63,7 @@ export class StickyThingDirective implements OnInit, AfterViewInit, OnDestroy {
* The field represents some position values in normal (not sticky) mode.
* If the browser size or the content of the page changes, this value must be recalculated.
* */
private scroll$ = new Subject<any>();
private scroll$ = new Subject<number>();
private scrollThrottled$: Observable<number>;


Expand All @@ -81,7 +83,6 @@ export class StickyThingDirective implements OnInit, AfterViewInit, OnDestroy {
this.scrollThrottled$ = this.scroll$
.pipe(
throttleTime(0, animationFrame),
map(() => window.pageYOffset),
share()
);

Expand Down Expand Up @@ -169,19 +170,49 @@ export class StickyThingDirective implements OnInit, AfterViewInit, OnDestroy {
}
}

@HostListener('window:scroll', [])
adapter(): void {
setupListener(): void {
if (isPlatformBrowser(this.platformId)) {
this.scroll$.next();
const target = this.getScrollTarget();
target.addEventListener('scroll', this.listener);
}
}

ngOnDestroy(): void {
this.componentDestroyed.next();
removeListener() {
if (isPlatformBrowser(this.platformId)) {
const target = this.getScrollTarget();
target.removeEventListener('scroll', this.listener);
}
}

listener = (e: Event) => {
const upperScreenEdgeAt = (e.target as HTMLElement).scrollTop || window.pageYOffset;
this.scroll$.next(upperScreenEdgeAt);
};


ngOnInit(): void {
this.checkSetup();
this.setupListener();

}

ngOnDestroy(): void {
this.componentDestroyed.next();
this.removeListener();
}

private getScrollTarget(): Element | Window {

let target: Element | Window;

if (this.scrollContainer && typeof this.scrollContainer === 'string') {
target = document.querySelector(this.scrollContainer);
} else if (this.scrollContainer && this.scrollContainer instanceof HTMLElement) {
target = this.scrollContainer;
} else {
target = window;
}
return target;
}

getComputedStyle(el: HTMLElement): ClientRect | DOMRect {
Expand Down
21 changes: 20 additions & 1 deletion src/app/test-cases/posa-container/posa-container.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<div class="row">
<div class="col-6">
<div #spacer></div>
<div [spacer]="spacer" class="some-thing-sticky" stickyThing="">
<div [scrollContainer]="'.scroll-container'" [spacer]="spacer" class="some-thing-sticky" stickyThing="">
Scroll by!
</div>
</div>
Expand All @@ -17,3 +17,22 @@
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>


<div class="another-scrollable-container">
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
<div>Hello</div>
</div>
13 changes: 13 additions & 0 deletions src/app/test-cases/posa-container/posa-container.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,16 @@
padding: 15px;
color: #000;
}

.another-scrollable-container {
width: 150px;
height: 100px;
overflow: auto;

div {
background-color: #fff;
border: 1px solid #333;
padding: 15px;
width: 200px;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component, OnInit} from '@angular/core';
import {Component, HostBinding, OnInit} from '@angular/core';

@Component({
selector: 'demo-posa-container',
Expand All @@ -7,6 +7,8 @@ import {Component, OnInit} from '@angular/core';
})
export class PosaContainerComponent implements OnInit {

@HostBinding('class') class = 'scroll-container';

constructor() {
}

Expand Down

0 comments on commit 78c315d

Please sign in to comment.