diff --git a/src/cdk/drag-drop/directives/drag.spec.ts b/src/cdk/drag-drop/directives/drag.spec.ts index 30b4eca62e33..7cd3aeda05b2 100644 --- a/src/cdk/drag-drop/directives/drag.spec.ts +++ b/src/cdk/drag-drop/directives/drag.spec.ts @@ -694,7 +694,18 @@ describe('CdkDrag', () => { it('should allow for dragging to be constrained to an element', fakeAsync(() => { const fixture = createComponent(StandaloneDraggable); - fixture.componentInstance.boundarySelector = '.wrapper'; + fixture.componentInstance.boundary = '.wrapper'; + fixture.detectChanges(); + const dragElement = fixture.componentInstance.dragElement.nativeElement; + + expect(dragElement.style.transform).toBeFalsy(); + dragElementViaMouse(fixture, dragElement, 300, 300); + expect(dragElement.style.transform).toBe('translate3d(100px, 100px, 0px)'); + })); + + it('should be able to pass in a DOM node as the boundary', fakeAsync(() => { + const fixture = createComponent(StandaloneDraggable); + fixture.componentInstance.boundary = fixture.nativeElement.querySelector('.wrapper'); fixture.detectChanges(); const dragElement = fixture.componentInstance.dragElement.nativeElement; @@ -3225,7 +3236,7 @@ describe('CdkDrag', () => {
Point; freeDragPosition?: {x: number, y: number}; diff --git a/src/cdk/drag-drop/directives/drag.ts b/src/cdk/drag-drop/directives/drag.ts index 7e33eec973fa..d8a30ca3327b 100644 --- a/src/cdk/drag-drop/directives/drag.ts +++ b/src/cdk/drag-drop/directives/drag.ts @@ -28,8 +28,9 @@ import { OnChanges, SimpleChanges, ChangeDetectorRef, + isDevMode, } from '@angular/core'; -import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion'; +import {coerceBooleanProperty, coerceNumberProperty, coerceElement} from '@angular/cdk/coercion'; import {Observable, Observer, Subject, merge} from 'rxjs'; import {startWith, take, map, takeUntil, switchMap, tap} from 'rxjs/operators'; import { @@ -100,12 +101,27 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { */ @Input('cdkDragRootElement') rootElementSelector: string; + /** + * Node or selector that will be used to determine the element to which the draggable's + * position will be constrained. If a string is passed in, it'll be used as a selector that + * will be matched starting from the element's parent and going up the DOM until a match + * has been found. + */ + @Input('cdkDragBoundary') boundaryElement: string | ElementRef | HTMLElement; + /** * Selector that will be used to determine the element to which the draggable's position will * be constrained. Matching starts from the element's parent and goes up the DOM until a matching - * element has been found. + * element has been found + * @deprecated Use `boundaryElement` instead. + * @breaking-change 9.0.0 */ - @Input('cdkDragBoundary') boundaryElementSelector: string; + get boundaryElementSelector(): string { + return typeof this.boundaryElement === 'string' ? this.boundaryElement : undefined!; + } + set boundaryElementSelector(selector: string) { + this.boundaryElement = selector; + } /** * Amount of milliseconds to wait after the user has put their @@ -292,10 +308,25 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { this._dragRef.withRootElement(rootElement || element); } - /** Gets the boundary element, based on the `boundaryElementSelector`. */ + /** Gets the boundary element, based on the `boundaryElement` value. */ private _getBoundaryElement() { - const selector = this.boundaryElementSelector; - return selector ? getClosestMatchingAncestor(this.element.nativeElement, selector) : null; + const boundary = this.boundaryElement; + + if (!boundary) { + return null; + } + + if (typeof boundary === 'string') { + return getClosestMatchingAncestor(this.element.nativeElement, boundary); + } + + const element = coerceElement(boundary); + + if (isDevMode() && !element.contains(this.element.nativeElement)) { + throw Error('Draggable element is not inside of the node passed into cdkDragBoundary.'); + } + + return element; } /** Syncs the inputs of the CdkDrag with the options of the underlying DragRef. */ diff --git a/tools/public_api_guard/cdk/drag-drop.d.ts b/tools/public_api_guard/cdk/drag-drop.d.ts index e94a7fafda05..8e5f158e8013 100644 --- a/tools/public_api_guard/cdk/drag-drop.d.ts +++ b/tools/public_api_guard/cdk/drag-drop.d.ts @@ -11,6 +11,7 @@ export declare class CdkDrag implements AfterViewInit, OnChanges, OnDes _handles: QueryList; _placeholderTemplate: CdkDragPlaceholder; _previewTemplate: CdkDragPreview; + boundaryElement: string | ElementRef | HTMLElement; boundaryElementSelector: string; constrainPosition?: (point: Point) => Point; data: T;