diff --git a/README.md b/README.md index 9282776..09b074d 100644 --- a/README.md +++ b/README.md @@ -554,6 +554,28 @@ Here we listen for `scroll` on the `div` and call `container.update()` in case t In order not to kill the performance, because the `scroll` event is called many many times, you may want to **throttle** it to only call `update` every 16ms or so. +### Does the `dtsSelectItem` directive need to be a direct child of the `dts-select-container`? + +As of version `4.1.0`, an injection token is used to pass the `SelectContainerComponent` parent to the directive. You can use this in any component nested within the `dts-select-container`. + +```ts +import { DTS_SELECT_CONTAINER } from 'ngx-drag-to-select'; + +@Component({...}) +export class TaskListComponent { + constructor( + @Inject(DTS_SELECT_CONTAINER) @Optional() + public container: SelectContainerComponent + ) {} +} +``` + +You can find an example of this in the [drag and drop example](https://github.com/d3lm/ngx-drag-to-select/blob/master/src/app/dragndrop). + +### Why is my `dtsSelectItem` directive not selecting when I click on it? + +If you are using the `dtsSelectItem` within a nested component then your mousedown/up events might being captured by another directive or component in your code. For example if you are using this libary with Angular CDK's DragDropModule, the mouse events are captured by the `cdkDrag` directive, [see here](https://github.com/angular/components/pull/19674). + ## Want to contribute? If you want to file a bug, contribute some code, or improve our documentation, read up on our [contributing guidelines](CONTRIBUTING.md) and [code of conduct](CODE_OF_CONDUCT.md), and check out [open issues](/issues). diff --git a/cypress/integration/drag-and-drop.spec.ts b/cypress/integration/drag-and-drop.spec.ts new file mode 100644 index 0000000..8567e5d --- /dev/null +++ b/cypress/integration/drag-and-drop.spec.ts @@ -0,0 +1,68 @@ +import { DEFAULT_CONFIG } from '../../projects/ngx-drag-to-select/src/lib/config'; + +import { getDoingList, getDragAndDropExample, getTodoList } from '../support/utils'; + +const SELECTED_CLASS = DEFAULT_CONFIG.selectedClass; + +describe('Drag And Drop', () => { + beforeEach(() => { + cy.visit('/'); + }); + + describe('Select on Drag', () => { + it('should start new selection', () => { + getDragAndDropExample().within(() => { + getTodoList() + .dispatch('mousedown', 'topLeft', { button: 0 }) + .getSelectItem(2) + .dispatch('mousemove') + .dispatch('mouseup'); + + cy.get('.selected').should('have.length', 3); + }); + }); + + it('should drag to new list', () => { + getDragAndDropExample().within(() => { + getTodoList() + // select first 3 items in list + .dispatch('mousedown', 'topLeft', { button: 0 }) + .getSelectItem(2) + .dispatch('mousemove') + .dispatch('mouseup') + // click on second item + .getSelectItem(1) + .dispatch('mousedown', { button: 0 }) + // drag to SelectItem in other list + .getSelectItem(5) + .wait(16) + .dispatch('mousemove') + .dispatch('mousemove') + .dispatch('mouseup'); + + getDoingList().within(() => { + cy.get('app-task').should('have.length', 5); + }); + }); + }); + + it('should reorder within list', () => { + getDragAndDropExample().within(() => { + getTodoList() + .dispatch('mousedown', 'topRight', { button: 0 }) + .getSelectItem(1) + .dispatch('mousemove') + .dispatch('mouseup') + .getSelectItem(0) + .dispatch('mousedown', 'bottom', { button: 0 }) + .getSelectItem(4) + .dispatch('mousemove') + .dispatch('mousemove') + .dispatch('mouseup'); + + cy.get('app-task').eq(0).should('contain', 'Open Ticket #1'); + cy.get('app-task').eq(1).should('contain', 'Open Ticket #2'); + }); + }); + }); +}); diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts index 5f2e640..fc12cb8 100644 --- a/cypress/support/utils.ts +++ b/cypress/support/utils.ts @@ -28,6 +28,10 @@ export const getMobileExample = () => { return cy.get('[data-cy="mobile"]'); }; +export const getDragAndDropExample = () => { + return cy.get('[data-cy="drag-and-drop"]'); +}; + export const getSelectCount = () => { return cy.get('[data-cy="select-count"]'); }; @@ -48,6 +52,18 @@ export const getClearButton = () => { return cy.get('[data-cy="clearSelection"]'); }; +export const getTodoList = () => { + return cy.get('[data-cy="todo-list"]'); +}; + +export const getDoingList = () => { + return cy.get('[data-cy="doing-list"]'); +}; + +export const getDoneList = () => { + return cy.get('[data-cy="done-list"]'); +}; + export const disableSelectOnDrag = () => { return cy.get('[data-cy="selectOnDrag"]').click(); }; diff --git a/projects/ngx-drag-to-select/src/lib/models.ts b/projects/ngx-drag-to-select/src/lib/models.ts index 4122c2f..5ebf228 100644 --- a/projects/ngx-drag-to-select/src/lib/models.ts +++ b/projects/ngx-drag-to-select/src/lib/models.ts @@ -62,3 +62,11 @@ export enum Action { Delete, None, } + +export interface SelectContainer { + selectedItems: T[]; + register(item: T): void; + unregister(item: T): void; +} + +export type ComponentType = new (...args: any[]) => T; diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 55cdea3..c79e675 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -8,13 +8,10 @@ import { Renderer2, ViewChild, NgZone, - ContentChildren, - QueryList, HostBinding, AfterViewInit, PLATFORM_ID, Inject, - AfterContentInit, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @@ -32,7 +29,6 @@ import { share, withLatestFrom, distinctUntilChanged, - observeOn, startWith, concatMapTo, first, @@ -41,7 +37,7 @@ import { import { SelectItemDirective, SELECT_ITEM_INSTANCE } from './select-item.directive'; import { ShortcutService } from './shortcut.service'; -import { createSelectBox, whenSelectBoxVisible, distinctKeyEvents } from './operators'; +import { createSelectBox, whenSelectBoxVisible } from './operators'; import { Action, @@ -52,6 +48,7 @@ import { UpdateActions, PredicateFn, BoundingBox, + SelectContainer, } from './models'; import { AUDIT_TIME, NO_SELECT_CLASS } from './constants'; @@ -67,6 +64,7 @@ import { hasMinimumSize, } from './utils'; import { KeyboardEventsService } from './keyboard-events.service'; +import { DTS_SELECT_CONTAINER } from './tokens'; @Component({ selector: 'dts-select-container', @@ -84,8 +82,9 @@ import { KeyboardEventsService } from './keyboard-events.service'; > `, styleUrls: ['./select-container.component.scss'], + providers: [{ provide: DTS_SELECT_CONTAINER, useExisting: SelectContainerComponent }], }) -export class SelectContainerComponent implements AfterViewInit, OnDestroy, AfterContentInit { +export class SelectContainerComponent implements AfterViewInit, OnDestroy, SelectContainer { host: SelectContainerHost; selectBoxStyles$: Observable>; selectBoxClasses$: Observable<{ [key: string]: boolean }>; @@ -93,9 +92,6 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After @ViewChild('selectBox', { static: true }) private $selectBox: ElementRef; - @ContentChildren(SelectItemDirective, { descendants: true }) - private $selectableItems: QueryList; - @Input() selectedItems: any; @Input() selectOnDrag = true; @Input() disabled = false; @@ -127,6 +123,8 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After private _newRangeStart = false; private _lastRangeSelection: Map = new Map(); + private _registry: Set = new Set(); + constructor( @Inject(PLATFORM_ID) private platformId: Object, private shortcuts: ShortcutService, @@ -258,12 +256,12 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } } - ngAfterContentInit() { - this._selectableItems = this.$selectableItems.toArray(); + updateSelectableItems() { + this._selectableItems = Array.from(this._registry); } selectAll() { - this.$selectableItems.forEach((item) => { + this._selectableItems.forEach((item) => { this._selectItem(item); }); } @@ -281,14 +279,25 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } clearSelection() { - this.$selectableItems.forEach((item) => { + this._selectableItems.forEach((item) => { this._deselectItem(item); }); } + register(item: SelectItemDirective) { + this._registry.add(item); + this.updateSelectableItems(); + } + + unregister(item: SelectItemDirective) { + this._registry.delete(item); + this.updateSelectableItems(); + this._removeItem(item, this.selectedItems); + } + update() { this._calculateBoundingClientRect(); - this.$selectableItems.forEach((item) => item.calculateBoundingClientRect()); + this._selectableItems.forEach((item) => item.calculateBoundingClientRect()); } ngOnDestroy() { @@ -335,21 +344,6 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After break; } }); - - // Update the container as well as all selectable items if the list has changed - this.$selectableItems.changes - .pipe(withLatestFrom(this._selectedItems$), observeOn(asyncScheduler), takeUntil(this.destroy$)) - .subscribe(([items, selectedItems]: [QueryList, any[]]) => { - const newList = items.toArray(); - this._selectableItems = newList; - const removedItems = selectedItems.filter((item) => !newList.includes(item.value)); - - if (removedItems.length) { - removedItems.forEach((item) => this._removeItem(item, selectedItems)); - } - - this.update(); - }); } private _observeBoundingRectChanges() { @@ -395,6 +389,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After } private _onMouseDown(event: MouseEvent) { + console.log('Mouse Down'); if (this.shortcuts.disableSelection(event) || this.disabled) { return; } @@ -446,7 +441,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After return; } - this.$selectableItems.forEach((item, index) => { + this._selectableItems.forEach((item, index) => { const itemRect = item.getBoundingClientRect(); const withinBoundingBox = inBoundingBox(mousePoint, itemRect); @@ -509,7 +504,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After private _selectItems(event: Event) { const selectionBox = calculateBoundingClientRect(this.$selectBox.nativeElement); - this.$selectableItems.forEach((item, index) => { + this._selectableItems.forEach((item, index) => { if (this._isExtendedSelection(event)) { this._extendedSelectionMode(selectionBox, item, event); } else { diff --git a/projects/ngx-drag-to-select/src/lib/select-item.directive.ts b/projects/ngx-drag-to-select/src/lib/select-item.directive.ts index 168cd4d..bccc1c5 100644 --- a/projects/ngx-drag-to-select/src/lib/select-item.directive.ts +++ b/projects/ngx-drag-to-select/src/lib/select-item.directive.ts @@ -10,10 +10,13 @@ import { Renderer2, OnInit, HostBinding, + Optional, + SkipSelf, + OnDestroy, } from '@angular/core'; -import { DragToSelectConfig, BoundingBox } from './models'; -import { CONFIG } from './tokens'; +import { DragToSelectConfig, BoundingBox, SelectContainer } from './models'; +import { CONFIG, DTS_SELECT_CONTAINER } from './tokens'; import { calculateBoundingClientRect } from './utils'; export const SELECT_ITEM_INSTANCE = Symbol(); @@ -25,7 +28,7 @@ export const SELECT_ITEM_INSTANCE = Symbol(); class: 'dts-select-item', }, }) -export class SelectItemDirective implements OnInit, DoCheck { +export class SelectItemDirective implements OnInit, DoCheck, OnDestroy { private _boundingClientRect: BoundingBox | undefined; selected = false; @@ -41,18 +44,24 @@ export class SelectItemDirective implements OnInit, DoCheck { constructor( @Inject(CONFIG) private config: DragToSelectConfig, @Inject(PLATFORM_ID) private platformId: Object, + @Inject(DTS_SELECT_CONTAINER) @Optional() @SkipSelf() public container: SelectContainer, private host: ElementRef, private renderer: Renderer2 ) {} ngOnInit() { this.nativeElememnt[SELECT_ITEM_INSTANCE] = this; + this.container.register(this); } ngDoCheck() { this.applySelectedClass(); } + ngOnDestroy() { + this.container.unregister(this); + } + toggleRangeStart() { this.rangeStart = !this.rangeStart; } diff --git a/projects/ngx-drag-to-select/src/lib/tokens.ts b/projects/ngx-drag-to-select/src/lib/tokens.ts index 6e3122b..87d3856 100644 --- a/projects/ngx-drag-to-select/src/lib/tokens.ts +++ b/projects/ngx-drag-to-select/src/lib/tokens.ts @@ -1,5 +1,6 @@ import { InjectionToken } from '@angular/core'; -import { DragToSelectConfig } from './models'; +import { DragToSelectConfig, SelectContainer, ComponentType } from './models'; export const CONFIG = new InjectionToken('DRAG_TO_SELECT_CONFIG'); export const USER_CONFIG = new InjectionToken('USER_CONFIG'); +export const DTS_SELECT_CONTAINER = new InjectionToken>('SelectContainerComponent'); diff --git a/projects/ngx-drag-to-select/src/public_api.ts b/projects/ngx-drag-to-select/src/public_api.ts index e1d010e..aab3305 100644 --- a/projects/ngx-drag-to-select/src/public_api.ts +++ b/projects/ngx-drag-to-select/src/public_api.ts @@ -5,3 +5,4 @@ export * from './lib/drag-to-select.module'; export * from './lib/select-container.component'; export * from './lib/select-item.directive'; +export { DTS_SELECT_CONTAINER } from './lib/tokens'; diff --git a/src/app/app.component.html b/src/app/app.component.html index 70c95fe..9e770ba 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -4,11 +4,15 @@

Keyboard Shortcuts

- + + + - + + + @@ -21,9 +25,8 @@

Select on Drag Disable - Disable Range Selection + Disable Range Selection + Select Mode Select with Shortcut @@ -43,8 +46,7 @@

[disabled]="disable" [disableRangeSelection]="disableRangeSelection" [selectOnDrag]="selectOnDrag" - [selectWithShortcut]="selectWithShortcut" - > + [selectWithShortcut]="selectWithShortcut"> {{ document.name }} @@ -64,12 +66,25 @@

Meta Information

+
+

+ Drag & Drop Demo + SOURCE +

+ + + +
+

- Mobile Demo SOURCE + Mobile Demo + SOURCE

-
+
+ +
- + \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a7bcc84..2f00890 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -9,6 +9,8 @@ import { MatChipsModule } from '@angular/material/chips'; import { MatTabsModule } from '@angular/material/tabs'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { DragDropModule } from '@angular/cdk/drag-drop'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -19,6 +21,9 @@ import { AppComponent } from './app.component'; import { FooterComponent } from './footer/footer.component'; import { HeaderComponent } from './header/header.component'; import { PhoneComponent } from './phone/phone.component'; +import { DragAndDropComponent } from './drag-and-drop/drag-and-drop.component'; +import { TaskComponent } from './drag-and-drop/task/task.component'; +import { TaskListComponent } from './drag-and-drop/task-list/task-list.component'; import { KeyComponent, @@ -36,6 +41,8 @@ const MATERIAL_MODULES = [ MatTabsModule, MatIconModule, MatButtonModule, + MatCardModule, + DragDropModule, ]; @NgModule({ @@ -49,6 +56,9 @@ const MATERIAL_MODULES = [ FooterComponent, HeaderComponent, PhoneComponent, + DragAndDropComponent, + TaskComponent, + TaskListComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'demo-app' }), diff --git a/src/app/drag-and-drop/drag-and-drop.component.html b/src/app/drag-and-drop/drag-and-drop.component.html new file mode 100644 index 0000000..5fde904 --- /dev/null +++ b/src/app/drag-and-drop/drag-and-drop.component.html @@ -0,0 +1,7 @@ + +
+ + + +
+
\ No newline at end of file diff --git a/src/app/drag-and-drop/drag-and-drop.component.scss b/src/app/drag-and-drop/drag-and-drop.component.scss new file mode 100644 index 0000000..4497a6f --- /dev/null +++ b/src/app/drag-and-drop/drag-and-drop.component.scss @@ -0,0 +1,20 @@ +.list-wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 1rem; + min-height: 400px; +} + +.cdk-drag-preview { + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} + +.cdk-drag-placeholder { + opacity: 0; +} + +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} diff --git a/src/app/drag-and-drop/drag-and-drop.component.ts b/src/app/drag-and-drop/drag-and-drop.component.ts new file mode 100644 index 0000000..9d81538 --- /dev/null +++ b/src/app/drag-and-drop/drag-and-drop.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-drag-and-drop', + templateUrl: './drag-and-drop.component.html', + styleUrls: ['./drag-and-drop.component.scss'], +}) +export class DragAndDropComponent { + todo = ['Next Task', 'Very Important Item', 'Open Ticket #1', 'Open Ticket #2', 'Not Important Task']; + doing = ['High Priority Task', 'In Progress Item']; + done = ['Completed Item']; + selectedItems: any[] = []; +} diff --git a/src/app/drag-and-drop/task-list/task-list.component.html b/src/app/drag-and-drop/task-list/task-list.component.html new file mode 100644 index 0000000..6a726fe --- /dev/null +++ b/src/app/drag-and-drop/task-list/task-list.component.html @@ -0,0 +1,20 @@ +

{{title}}

+ +
+ +
+ {{ selected }} +
+
+ {{ selected }} +
+
+
\ No newline at end of file diff --git a/src/app/drag-and-drop/task-list/task-list.component.scss b/src/app/drag-and-drop/task-list/task-list.component.scss new file mode 100644 index 0000000..4691402 --- /dev/null +++ b/src/app/drag-and-drop/task-list/task-list.component.scss @@ -0,0 +1,72 @@ +:host { + background-color: #ebecf0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + flex-direction: column; + max-height: 100%; + position: relative; + white-space: normal; +} + +.list-header { + padding: 0.5rem; +} + +.list-cards { + margin: 0 4px; + padding: 0 4px; + display: grid; + grid-template-columns: 1fr; + grid-auto-rows: min-content; + gap: 0.4rem; + height: -webkit-fill-available; +} + +.list-cards.cdk-drop-list-dragging app-task:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +:host(.item-dragging) { + app-task.selected:not(.cdk-drag-placeholder) { + display: none; + } +} + +.drag-placeholder-container { + display: flex; + flex-flow: column; + gap: 0.5rem; + min-height: 53px; + height: min-content; + + mat-card { + opacity: 0.5; + } +} + +.drag-preview-container { + gap: 0.5rem; + position: relative; + + mat-card { + position: absolute; + width: 200px; + top: -10px; + left: -25px; + } + + mat-card:nth-child(2) { + left: -40px; + top: -10px; + transform: rotate(-1deg); + z-index: -1; + } + + mat-card:nth-child(3) { + top: -5px; + left: -20px; + transform: rotate(1deg); + z-index: -2; + } +} diff --git a/src/app/drag-and-drop/task-list/task-list.component.ts b/src/app/drag-and-drop/task-list/task-list.component.ts new file mode 100644 index 0000000..f3eadda --- /dev/null +++ b/src/app/drag-and-drop/task-list/task-list.component.ts @@ -0,0 +1,81 @@ +import { CdkDragStart, CdkDragDrop } from '@angular/cdk/drag-drop'; +import { Component, ElementRef, HostBinding, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; +import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; + +@Component({ + selector: 'app-task-list', + styleUrls: ['./task-list.component.scss'], + templateUrl: './task-list.component.html', +}) +export class TaskListComponent { + @Input() title = 'Tasks'; + @Input() tasks = []; + + @HostBinding('class.item-dragging') + dragging = false; + + // CdkDragModule only supports dragging a single dom element + private selectDomRefs: { parent: Node; node: Node }[] = []; + + constructor( + @Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent, + private element: ElementRef + ) {} + + dragStarted(ev: CdkDragStart, index: number): void { + this.dragging = !!ev.source._dragRef; + this.container.selectItems((item) => { + return item === this.tasks[index]; + }); + + /** + * We remove the selected elements from the DOM, because the + * CdkDragDropModule includes them when reordering even if they. + * are hidden. + **/ + this.selectDomRefs = []; + this.element.nativeElement.querySelectorAll('.selected').forEach((node: Node) => { + this.selectDomRefs.push({ parent: node.parentNode, node }); + node.parentNode.removeChild(node); + }); + } + + dragEnded(): void { + /** + * Add the DOM elements back in because the Angular refs are still + * bound to them. + **/ + this.selectDomRefs.forEach(({ parent, node }) => { + parent.appendChild(node); + }); + this.dragging = null; + } + + dropped(event: CdkDragDrop): void { + this.dragging = null; + const indices = this.container.selectedItems.map((it) => event.previousContainer.data.findIndex((i) => it === i)); + indices.sort().reverse(); + indices.forEach((idx) => { + this.tasks.splice(idx, 1); + }); + + setTimeout(() => this.container.clearSelection()); + } + + drop(event: CdkDragDrop) { + const spliceIntoIndex = event.currentIndex; + this.tasks.splice(spliceIntoIndex, 0, ...this.container.selectedItems); + + /** + * Caution! + * When drop event is within the same drop-list the bounding box of + * drag events might not update to there new positions. Use the + * `update` method from the `SelectContainerComponent` to force the + * bounding boxes to be recalculated. + * This is put behind `setTimeout` because we have to wait until the next + * frame before angular change detection has updated the dom. + * */ + setTimeout(() => this.container.update()); + } +} diff --git a/src/app/drag-and-drop/task/task.component.html b/src/app/drag-and-drop/task/task.component.html new file mode 100644 index 0000000..1a52761 --- /dev/null +++ b/src/app/drag-and-drop/task/task.component.html @@ -0,0 +1,5 @@ + + {{ item }} + \ No newline at end of file diff --git a/src/app/drag-and-drop/task/task.component.scss b/src/app/drag-and-drop/task/task.component.scss new file mode 100644 index 0000000..2b3cb9e --- /dev/null +++ b/src/app/drag-and-drop/task/task.component.scss @@ -0,0 +1,13 @@ +:host { + display: block; + + &.selected { + mat-card { + border: 1px solid #2196f3; + } + } +} + +mat-card { + border: 1px solid transparent; +} diff --git a/src/app/drag-and-drop/task/task.component.ts b/src/app/drag-and-drop/task/task.component.ts new file mode 100644 index 0000000..b2279c9 --- /dev/null +++ b/src/app/drag-and-drop/task/task.component.ts @@ -0,0 +1,18 @@ +import { Component, Inject, Input, Optional, SkipSelf } from '@angular/core'; +import { SelectContainerComponent } from 'projects/ngx-drag-to-select/src/public_api'; +import { DTS_SELECT_CONTAINER } from 'projects/ngx-drag-to-select/src/lib/tokens'; + +@Component({ + selector: 'app-task', + styleUrls: ['./task.component.scss'], + templateUrl: './task.component.html', +}) +export class TaskComponent { + @Input() item = ''; + constructor(@Inject(DTS_SELECT_CONTAINER) @Optional() public container: SelectContainerComponent) {} + + select() { + this.container.clearSelection(); + this.container.selectItems((it) => it === this.item); + } +}