### File

`src/dropdown/dropdown.service.ts`

### Index

###### Properties
Protected _offset Protected animationFrameSubscription Protected menuInstance
###### Methods
appendToBody appendToDropdown ngOnDestroy Protected positionDropdown updatePosition
###### Accessors
offset

### Constructor

`constructor(placeholderService: PlaceholderService, animationFrameService: AnimationFrameService)`
Defined in src/dropdown/dropdown.service.ts:29
Parameters :
Name | Type | Optional
placeholderService | `PlaceholderService` | No
animationFrameService | `AnimationFrameService` | No

### Methods

appendToBody
`appendToBody(parentRef: HTMLElement, menuRef: HTMLElement, classList)`
Defined in src/dropdown/dropdown.service.ts:43
Appends the menu to the body, or a `ibm-placeholder` (if defined) Parameters :
Name | Type | Optional | Description
parentRef | `HTMLElement` | No | `container to position relative to`
menuRef | `HTMLElement` | No | `menu to be appended to body`
classList |  | No | `any extra classes we should wrap the container with`
Returns : `HTMLElement`

appendToDropdown
`appendToDropdown(hostRef: HTMLElement)`
Defined in src/dropdown/dropdown.service.ts:73
Reattach the dropdown menu to the parent container Parameters :
Name | Type | Optional | Description
hostRef | `HTMLElement` | No | `container to append to`
Returns : `HTMLElement`

ngOnDestroy
`ngOnDestroy()`
Defined in src/dropdown/dropdown.service.ts:98
Returns : `void`

Protected positionDropdown
`positionDropdown(parentRef, menuRef)`
Defined in src/dropdown/dropdown.service.ts:102
Parameters :
Name | Optional
parentRef | No
menuRef | No
Returns : `void`

updatePosition
`updatePosition(parentRef)`
Defined in src/dropdown/dropdown.service.ts:94
position an open dropdown relative to the given parentRef Parameters :
Name | Optional
parentRef | No
Returns : `void`

### Properties

Protected _offset
`_offset: ```
Default value : `defaultOffset`
Defined in src/dropdown/dropdown.service.ts:29

Protected animationFrameSubscription
`animationFrameSubscription: ```
Default value : `new Subscription()`
Defined in src/dropdown/dropdown.service.ts:27
Maintains an Event Observable Subscription for the global requestAnimationFrame. requestAnimationFrame is tracked only if the `Dropdown` is appended to the body otherwise we don't need it

Protected menuInstance
`menuInstance: `HTMLElement``
Type : `HTMLElement`
Defined in src/dropdown/dropdown.service.ts:21
reference to the body appended menu

### Accessors

offset
get `offset()`
Defined in src/dropdown/dropdown.service.ts:15
set `offset(value: literal type)`
Defined in src/dropdown/dropdown.service.ts:11
Parameters :
Name | Type | Optional
value | `literal type` | No
Returns : `void`

    import { Injectable, ElementRef, OnDestroy } from "@angular/core";
    import { PlaceholderService } from "./../placeholder/placeholder.module";
    import { Subscription } from "rxjs";
    import { position } from "@carbon/utils-position";
    import { AnimationFrameService } from "./../utils/utils.module";

    const defaultOffset = { top: 0, left: 0 };

    @Injectable()
    export class DropdownService implements OnDestroy {
    	public set offset(value: { top?: number, left?: number }) {
    		this._offset = Object.assign({}, defaultOffset, value);
    	}

    	public get offset() {
    		return this._offset;
    	}
    	/**
    	 * reference to the body appended menu
    	 */
    	protected menuInstance: HTMLElement;

    	/**
    	 * Maintains an Event Observable Subscription for the global requestAnimationFrame.
    	 * requestAnimationFrame is tracked only if the `Dropdown` is appended to the body otherwise we don't need it
    	 */
    	protected animationFrameSubscription = new Subscription();

    	protected _offset = defaultOffset;

    	constructor(
    		protected placeholderService: PlaceholderService,
    		protected animationFrameService: AnimationFrameService
    	) {}

    	/**
    	 * Appends the menu to the body, or a `ibm-placeholder` (if defined)
    	 *
    	 * @param parentRef container to position relative to
    	 * @param menuRef menu to be appended to body
    	 * @param classList any extra classes we should wrap the container with
    	 */
    	appendToBody(parentRef: HTMLElement, menuRef: HTMLElement, classList): HTMLElement {
    		// build the dropdown list container
    		menuRef.style.display = "block";
    		const dropdownWrapper = document.createElement("div");
    		dropdownWrapper.className = `dropdown ${classList}`;
    		dropdownWrapper.style.width = parentRef.offsetWidth + "px";
    		dropdownWrapper.style.position = "absolute";
    		dropdownWrapper.appendChild(menuRef);

    		// append it to the placeholder
    		if (this.placeholderService.hasPlaceholderRef()) {
    			this.placeholderService.appendElement(dropdownWrapper);
    			// or append it directly to the body
    		} else {
    			document.body.appendChild(dropdownWrapper);
    		}

    		this.menuInstance = dropdownWrapper;

    		this.animationFrameSubscription = this.animationFrameService.tick.subscribe(() => {
    			this.positionDropdown(parentRef, dropdownWrapper);
    		});

    		return dropdownWrapper;
    	}

    	/**
    	 * Reattach the dropdown menu to the parent container
    	 * @param hostRef container to append to
    	 */
    	appendToDropdown(hostRef: HTMLElement): HTMLElement {
    		// if the instance is already removed don't try and remove it again
    		if (!this.menuInstance) { return; }
    		const instance = this.menuInstance;
    		const menu = instance.firstElementChild as HTMLElement;
    		// clean up the instance
    		this.menuInstance = null;
    		menu.style.display = "none";
    		hostRef.appendChild(menu);
    		this.animationFrameSubscription.unsubscribe();
    		if (this.placeholderService.hasPlaceholderRef() && this.placeholderService.hasElement(instance)) {
    			this.placeholderService.removeElement(instance);
    		} else if (document.body.contains(instance)) {
    			document.body.removeChild(instance);
    		}
    		return instance;
    	}

    	/**
    	 * position an open dropdown relative to the given parentRef
    	 */
    	updatePosition(parentRef) {
    		this.positionDropdown(parentRef, this.menuInstance);
    	}

    	ngOnDestroy() {
    		this.animationFrameSubscription.unsubscribe();
    	}

    	protected positionDropdown(parentRef, menuRef) {
    		if (!menuRef) {
    			return;
    		}

    		let leftOffset = 0;

    		const boxMenu = menuRef.querySelector(".bx--list-box__menu");

    		// If the parentRef and boxMenu are in a different left position relative to the
    		// window, the the boxMenu position has already been flipped and a check needs to be done
    		// to see if it needs to stay flipped.
    		if (parentRef.getBoundingClientRect().left !== boxMenu.getBoundingClientRect().left) {
    			// The getBoundingClientRect().right of the boxMenu if it were hypothetically flipped
    			// back into the original position before the flip.
    			const testBoxMenuRightEdgePos =
    				parentRef.getBoundingClientRect().left - boxMenu.getBoundingClientRect().left + boxMenu.getBoundingClientRect().right;

    			if (testBoxMenuRightEdgePos > (window.innerWidth || document.documentElement.clientWidth)) {
    				leftOffset = parentRef.offsetWidth - boxMenu.offsetWidth;
    			}
    		// If it has not already been flipped, check if it is necessary to flip, ie. if the
    		// boxMenu is outside of the right viewPort.
    		} else if (boxMenu.getBoundingClientRect().right > (window.innerWidth || document.documentElement.clientWidth)) {
    			leftOffset = parentRef.offsetWidth - boxMenu.offsetWidth;
    		}

    		let pos = position.findAbsolute(parentRef, menuRef, "bottom");
    		pos = position.addOffset(pos, this.offset.top, this.offset.left + leftOffset);
    		position.setElement(menuRef, pos);
    	}
    }

# result-matching ""

# No results matching ""