### File

`src/dropdown/scrollable-list.directive.ts`

### Implements

`OnChanges` `AfterViewInit`

### Metadata

Selector | `[ibmScrollableList]`

### Index

###### Properties

- Protected canScrollDown
- Protected canScrollUp
- Protected hoverScrollInterval
- Protected lastTouch
- Protected list

###### Methods

- Protected checkScrollArrows
- Protected hoverScrollBy
- ngAfterViewInit
- ngOnChanges
- Protected onHoverDown
- Protected onHoverUp
- Public updateScrollHeight

###### Inputs

- nScrollableList
- scrollBy
- scrollDownTarget
- scrollEnabled
- scrollUpTarget

###### HostListeners

- keydown
- touchmove
- touchstart
- wheel

### Constructor

`constructor(elementRef: ElementRef)`
Defined in src/dropdown/scrollable-list.directive.ts:44

Parameters :

Name | Type | Optional
elementRef | `ElementRef` | No

### Inputs

`nScrollableList` | Optional target list to scroll Type : `string` Default value : `null`
Defined in src/dropdown/scrollable-list.directive.ts:19

`scrollBy` | How many lines to scroll by each time `wheel` fires Defaults to 10 - based on testing this isn't too fast or slow on any platform Default value : `10`
Defined in src/dropdown/scrollable-list.directive.ts:36

`scrollDownTarget` | Sets the target used for hover scrolling down Type : `HTMLElement`
Defined in src/dropdown/scrollable-list.directive.ts:31

`scrollEnabled` | Enables or disables scrolling for the whole directive Default value : `true`
Defined in src/dropdown/scrollable-list.directive.ts:23

`scrollUpTarget` | Sets the target used for hover scrolling up Type : `HTMLElement`
Defined in src/dropdown/scrollable-list.directive.ts:27

### HostListeners

keydown
Arguments : `'$event'`
`keydown(event)`
Defined in src/dropdown/scrollable-list.directive.ts:182

touchmove
Arguments : `'$event'`
`touchmove(event)`
Defined in src/dropdown/scrollable-list.directive.ts:148

touchstart
Arguments : `'$event'`
`touchstart(event)`
Defined in src/dropdown/scrollable-list.directive.ts:141

wheel
Arguments : `'$event'`
`wheel(event)`
Defined in src/dropdown/scrollable-list.directive.ts:126

### Methods

Protected checkScrollArrows
`checkScrollArrows()`
Defined in src/dropdown/scrollable-list.directive.ts:96
Returns : `void`

Protected hoverScrollBy
`hoverScrollBy(hovering, amount)`
Defined in src/dropdown/scrollable-list.directive.ts:159

Parameters :

Name | Optional
hovering | No
amount | No

Returns : `void`

ngAfterViewInit
`ngAfterViewInit()`
Defined in src/dropdown/scrollable-list.directive.ts:73
Returns : `void`

ngOnChanges
`ngOnChanges(changes: SimpleChanges)`
Defined in src/dropdown/scrollable-list.directive.ts:48

Parameters :

Name | Type | Optional
changes | `SimpleChanges` | No

Returns : `void`

Protected onHoverDown
`onHoverDown(hovering)`
Defined in src/dropdown/scrollable-list.directive.ts:177

Parameters :

Name | Optional
hovering | No

Returns : `void`

Protected onHoverUp
`onHoverUp(hovering)`
Defined in src/dropdown/scrollable-list.directive.ts:170

Parameters :

Name | Optional
hovering | No

Returns : `void`

Public updateScrollHeight
`updateScrollHeight()`
Defined in src/dropdown/scrollable-list.directive.ts:83
Returns : `void`

### Properties

Protected canScrollDown
`canScrollDown: ```
Default value : `false`
Defined in src/dropdown/scrollable-list.directive.ts:43

Protected canScrollUp
`canScrollUp: ```
Default value : `false`
Defined in src/dropdown/scrollable-list.directive.ts:42

Protected hoverScrollInterval
`hoverScrollInterval: ```
Defined in src/dropdown/scrollable-list.directive.ts:39

Protected lastTouch
`lastTouch: ```
Defined in src/dropdown/scrollable-list.directive.ts:41

Protected list
`list: ```
Default value : `this.elementRef.nativeElement`
Defined in src/dropdown/scrollable-list.directive.ts:44

    import {
    	Input,
    	Directive,
    	ElementRef,
    	HostListener,
    	OnChanges,
    	SimpleChanges,
    	AfterViewInit
    } from "@angular/core";

    @Directive({
    	selector: "[ibmScrollableList]",
    	exportAs: "scrollable-list"
    })
    export class ScrollableList implements OnChanges, AfterViewInit {
    	/**
    	 * Optional target list to scroll
    	 */
    	@Input() nScrollableList: string = null;
    	/**
    	 * Enables or disables scrolling for the whole directive
    	 */
    	@Input() scrollEnabled = true;
    	/**
    	 * Sets the target used for hover scrolling up
    	 */
    	@Input() scrollUpTarget: HTMLElement;
    	/**
    	 * Sets the target used for hover scrolling down
    	 */
    	@Input() scrollDownTarget: HTMLElement;
    	/**
    	 * How many lines to scroll by each time `wheel` fires
    	 * Defaults to 10 - based on testing this isn't too fast or slow on any platform
    	 */
    	@Input() scrollBy = 10;

    	// keeps track of the setInterval for hover scrolling
    	protected hoverScrollInterval;
    	// tracks the last touch event
    	protected lastTouch;
    	protected canScrollUp = false;
    	protected canScrollDown = false;
    	protected list = this.elementRef.nativeElement;

    	constructor(protected elementRef: ElementRef) {}

    	ngOnChanges(changes: SimpleChanges) {
    		if (changes.scrollEnabled) {
    			if (changes.scrollEnabled.currentValue) {
    				this.list.style.overflow = "hidden";
    				this.scrollUpTarget.style.display = "flex";
    				this.scrollDownTarget.style.display = "flex";
    				this.canScrollUp = true;
    				this.canScrollDown = true;
    				this.updateScrollHeight();
    				this.checkScrollArrows();
    				setTimeout(() => {
    					this.checkScrollArrows();
    				});
    			} else {
    				this.scrollUpTarget.style.display = "none";
    				this.scrollDownTarget.style.display = "none";
    				this.canScrollUp = false;
    				this.canScrollDown = false;
    				this.list.style.height = null;
    				this.list.style.overflow = null;
    				clearInterval(this.hoverScrollInterval);
    			}
    		}
    	}

    	ngAfterViewInit() {
    		if (this.nScrollableList) {
    			this.list = this.elementRef.nativeElement.querySelector(this.nScrollableList);
    		}
    		this.scrollUpTarget.addEventListener("mouseover", () => this.onHoverUp(true));
    		this.scrollUpTarget.addEventListener("mouseout", () => this.onHoverUp(false));
    		this.scrollDownTarget.addEventListener("mouseover", () => this.onHoverDown(true));
    		this.scrollDownTarget.addEventListener("mouseout", () => this.onHoverDown(false));
    	}

    	public updateScrollHeight() {
    		if (this.scrollEnabled) {
    			const container = this.elementRef.nativeElement.parentElement;
    			const containerRect = container.getBoundingClientRect();
    			const innerHeightDiff = this.list.getBoundingClientRect().top - containerRect.top;
    			const outerHeightDiff = containerRect.height - (containerRect.bottom - window.innerHeight);
    			// 40 gives us some padding between the bottom of the list,
    			// the bottom of the window, and the scroll down button
    			const height = outerHeightDiff - innerHeightDiff - 40;
    			this.list.style.height = `${height}px`;
    		}
    	}

    	protected checkScrollArrows() {
    		const scrollUpHeight = this.scrollUpTarget.offsetHeight;
    		const scrollDownHeight = this.scrollDownTarget.offsetHeight;
    		if (this.list.scrollTop === 0) {
    			if (this.canScrollUp) {
    				this.list.style.height = `${parseInt(this.list.style.height, 10) + scrollUpHeight}px`;
    			}
    			this.scrollUpTarget.style.display = "none";
    			this.canScrollUp = false;
    		} else if (this.list.scrollTop === this.list.scrollTopMax) {
    			if (this.canScrollDown) {
    				this.list.style.height = `${parseInt(this.list.style.height, 10) + scrollDownHeight}px`;
    			}
    			this.scrollDownTarget.style.display = "none";
    			this.canScrollDown = false;
    		} else {
    			if (!this.canScrollUp) {
    				this.list.style.height = `${parseInt(this.list.style.height, 10) - scrollUpHeight}px`;
    			}
    			if (!this.canScrollDown) {
    				this.list.style.height = `${parseInt(this.list.style.height, 10) - scrollDownHeight}px`;
    			}
    			this.scrollUpTarget.style.display = "flex";
    			this.scrollDownTarget.style.display = "flex";
    			this.canScrollUp = true;
    			this.canScrollDown = true;
    		}
    	}

    	@HostListener("wheel", ["$event"])
    	protected onWheel(event) {
    		if (event.deltaY < 0) {
    			this.list.scrollTop -= this.scrollBy;
    		} else {
    			this.list.scrollTop += this.scrollBy;
    		}
    		// only prevent the parent/window from scrolling if we can scroll
    		if (!(this.list.scrollTop === this.list.scrollTopMax || this.list.scrollTop === 0)) {
    			event.preventDefault();
    			event.stopPropagation();
    		}
    		this.checkScrollArrows();
    	}

    	@HostListener("touchstart", ["$event"])
    	protected onTouchStart(event) {
    		if (event.touches[0]) {
    			this.lastTouch = event.touches[0].clientY;
    		}
    	}

    	@HostListener("touchmove", ["$event"])
    	protected onTouchMove(event) {
    		event.preventDefault();
    		event.stopPropagation();
    		if (event.touches[0]) {
    			const touch = event.touches[0];
    			this.list.scrollTop += this.lastTouch - touch.clientY;
    			this.lastTouch = touch.clientY;
    			this.checkScrollArrows();
    		}
    	}

    	protected hoverScrollBy(hovering, amount) {
    		if (hovering) {
    			this.hoverScrollInterval = setInterval(() => {
    				this.list.scrollTop += amount;
    				this.checkScrollArrows();
    			}, 1);
    		} else {
    			clearInterval(this.hoverScrollInterval);
    		}
    	}

    	protected onHoverUp(hovering) {
    		// how many px/lines to scroll by on hover
    		// 3 is just a random number that felt good
    		// 1 and 2 are too slow, 4 works but it might be a tad fast
    		this.hoverScrollBy(hovering, -3);
    	}

    	protected onHoverDown(hovering) {
    		this.hoverScrollBy(hovering, 3);
    	}

    	@HostListener("keydown", ["$event"])
    	protected onKeyDown(event) {
    		if (event.key === "ArrowDown" || event.key === "ArrowUp") {
    			this.checkScrollArrows();
    		}
    	}
    }

# result-matching ""

# No results matching ""