Skip to content

Commit c4e4602

Browse files
felipepetucorafaellmarques
authored andcommitted
feat(table): implementa recurso drag and drop nas colunas da tabela
Implementa recurso `drag and drop` no componente table. fixes DTHFUI-7315
1 parent c8659d3 commit c4e4602

16 files changed

+354
-55
lines changed

projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
(p-change-visible-columns)="onChangeVisibleColumns($event)"
3131
(p-restore-column-manager)="onColumnRestoreManager($event)"
3232
(p-sort-by)="onSortBy($event)"
33+
[p-draggable]="draggable"
3334
>
3435
</po-table>
3536
</po-page-dynamic-search>

projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2770,4 +2770,9 @@ describe('PoPageDynamicTableComponent:', () => {
27702770
]);
27712771
});
27722772
});
2773+
it('draggable: should return false if draggable is false', () => {
2774+
component.draggable = false;
2775+
2776+
expect(component.draggable).toBeFalse();
2777+
});
27732778
});

projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ type UrlOrPoCustomizationFunction = string | (() => PoPageDynamicTableOptions);
128128
* <file name="sample-po-page-dynamic-table-hotels/sample-po-page-dynamic-table-hotels.component.html"> </file>
129129
* <file name="sample-po-page-dynamic-table-hotels/sample-po-page-dynamic-table-hotels.component.ts"> </file>
130130
* </example>
131+
*
132+
* <example name="po-page-dynamic-table-drag-and-drop" title="PO Page Dynamic Table - Drag and Drop">
133+
* <file name="sample-po-page-dynamic-table-drag-and-drop/sample-po-page-dynamic-table-drag-and-drop.component.html"> </file>
134+
* <file name="sample-po-page-dynamic-table-drag-and-drop/sample-po-page-dynamic-table-drag-and-drop.component.ts"> </file>
135+
* </example>
131136
*/
132137
@Component({
133138
selector: 'po-page-dynamic-table',
@@ -278,6 +283,7 @@ export class PoPageDynamicTableComponent extends PoPageDynamicListBaseComponent
278283
private _defaultPageActions: Array<PoPageAction> = [];
279284
private _defaultTableActions: Array<PoTableAction> = [];
280285
private _hideCloseDisclaimers: Array<string> = [];
286+
private _draggable = false;
281287

282288
private set defaultPageActions(value: Array<PoPageAction>) {
283289
this._defaultPageActions = value;
@@ -501,6 +507,22 @@ export class PoPageDynamicTableComponent extends PoPageDynamicListBaseComponent
501507
*/
502508
@Input('p-literals') searchLiterals: PoPageDynamicSearchLiterals;
503509

510+
/**
511+
* @optional
512+
*
513+
* @description
514+
*
515+
* Habilita o modo drag and drop para as colunas da tabela.
516+
*
517+
*/
518+
@Input('p-draggable') set draggable(value: boolean) {
519+
this._draggable = value;
520+
}
521+
522+
get draggable(): boolean {
523+
return this._draggable;
524+
}
525+
504526
constructor(
505527
private router: Router,
506528
private activatedRoute: ActivatedRoute,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<po-page-dynamic-table
2+
p-auto-router
3+
p-concat-filters
4+
p-keep-filters
5+
p-title="Po Page Dynamic Table - Drag and Drop"
6+
[p-draggable]="true"
7+
[p-height]="300"
8+
[p-infinite-scroll]="true"
9+
[p-fields]="fields"
10+
[p-service-api]="serviceApi"
11+
>
12+
</po-page-dynamic-table>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'sample-po-page-dynamic-table-drag-and-drop',
5+
templateUrl: './sample-po-page-dynamic-table-drag-and-drop.component.html'
6+
})
7+
export class SamplePoPageDynamicTableDragAndDropComponent {
8+
readonly serviceApi = 'https://po-sample-api.fly.dev/v1/people';
9+
10+
readonly fields: Array<any> = [
11+
{ property: 'id', key: true, visible: false },
12+
{ property: 'name', label: 'Name' },
13+
{ property: 'genre', label: 'Genre', sortable: false },
14+
{ property: 'city', label: 'City' }
15+
];
16+
17+
constructor() {}
18+
}

projects/ui/src/lib/components/po-table/po-table-base.component.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ export abstract class PoTableBaseComponent implements OnChanges, OnDestroy {
423423
private sortStore: PoTableColumnSort;
424424
private _infiniteScrollDistance?: number = 100;
425425
private _infiniteScroll?: boolean = false;
426+
private _draggable?: boolean = false;
426427

427428
/**
428429
* @description
@@ -814,6 +815,23 @@ export abstract class PoTableBaseComponent implements OnChanges, OnDestroy {
814815
return this.sortedColumn.ascending ? PoTableColumnSortType.Ascending : PoTableColumnSortType.Descending;
815816
}
816817

818+
/**
819+
* @optional
820+
*
821+
* @description
822+
*
823+
* Habilita o modo drag and drop para as colunas da tabela.
824+
*
825+
* @default `false`
826+
*/
827+
@Input('p-draggable') set draggable(draggable: boolean) {
828+
this._draggable = draggable || false;
829+
}
830+
831+
get draggable() {
832+
return this._draggable;
833+
}
834+
817835
constructor(
818836
private poDate: PoDateService,
819837
languageService: PoLanguageService,

projects/ui/src/lib/components/po-table/po-table.component.html

Lines changed: 169 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,13 @@
101101
}"
102102
>
103103
<thead>
104-
<tr [ngClass]="{ 'no-hover': hideSelectAll }" [class.po-table-header]="!height">
104+
<tr
105+
[ngClass]="{ 'no-hover': hideSelectAll, 'po-table-column-drag': this.isDraggable }"
106+
[class.po-table-header]="!height"
107+
cdkDropList
108+
cdkDropListOrientation="horizontal"
109+
(cdkDropListDropped)="drop($event)"
110+
>
105111
<th
106112
*ngIf="hasSelectableColumn"
107113
[style.pointer-events]="hideSelectAll ? 'none' : 'auto'"
@@ -134,32 +140,83 @@
134140
<ng-container *ngIf="height; then noColumnsWithHeight; else noColumnsWithoutHeight"> </ng-container>
135141
</th>
136142

137-
<th
138-
*ngFor="let column of mainColumns; let i = index; trackBy: trackBy"
139-
class="po-table-header-ellipsis"
140-
[style.width]="column.width"
141-
[style.max-width]="column.width"
142-
[style.min-width]="column.width"
143-
[attr.data-po-table-column-name]="column.label || (column.property | titlecase) | lowercase"
144-
[class.po-clickable]="(sort && column.sortable !== false) || hasService"
145-
[ngClass]="{
146-
'po-table-header-sorted':
147-
sort &&
148-
JSON.stringify(sortedColumn?.property) === JSON.stringify(column) &&
149-
(sortedColumn.ascending || !sortedColumn.ascending)
150-
}"
151-
[class.po-table-header-subtitle]="column.type === 'subtitle'"
152-
(click)="sortColumn(column)"
153-
>
154-
<div
155-
class="po-table-header-flex"
156-
[class.po-table-header-fixed-inner]="height"
157-
[class.po-table-header-flex-right]="column.type === 'currency' || column.type === 'number'"
158-
[class.po-table-header-flex-center]="column.type === 'subtitle'"
143+
<ng-container *ngIf="this.isDraggable; then tableDefaultThDragDrop; else tableDefaultThDefault"> </ng-container>
144+
<ng-template #tableDefaultThDragDrop>
145+
<th
146+
*ngFor="let column of mainColumns; let i = index; trackBy: trackBy"
147+
class="po-table-header-ellipsis"
148+
[style.width]="column.width"
149+
[style.max-width]="column.width"
150+
[style.min-width]="column.width"
151+
[attr.data-po-table-column-name]="column.label || (column.property | titlecase) | lowercase"
152+
[class.po-clickable]="(sort && column.sortable !== false) || hasService"
153+
[ngClass]="{
154+
'po-table-header-sorted':
155+
sort &&
156+
JSON.stringify(sortedColumn?.property) === JSON.stringify(column) &&
157+
(sortedColumn.ascending || !sortedColumn.ascending)
158+
}"
159+
[class.po-table-header-subtitle]="column.type === 'subtitle'"
160+
[class.po-table-column-drag-box]="this.isDraggable"
161+
(click)="sortColumn(column)"
162+
cdkDrag
163+
cdkDragLockAxis="x"
159164
>
160-
<ng-container *ngTemplateOutlet="contentHeaderTemplate; context: { $implicit: column }"> </ng-container>
161-
</div>
162-
</th>
165+
<div
166+
class="po-table-header-flex"
167+
[class.po-table-header-fixed-inner]="height"
168+
[class.po-table-header-flex-right]="column.type === 'currency' || column.type === 'number'"
169+
[class.po-table-header-flex-center]="column.type === 'subtitle'"
170+
>
171+
<ng-container *ngIf="this.isDraggable">
172+
<svg
173+
cdkDragHandle
174+
width="24"
175+
height="24"
176+
viewBox="0 0 24 24"
177+
fill="none"
178+
xmlns="http://www.w3.org/2000/svg"
179+
>
180+
<circle cx="9" cy="6" r="2" fill="black" />
181+
<circle cx="15" cy="6" r="2" fill="black" />
182+
<circle cx="9" cy="12" r="2" fill="black" />
183+
<circle cx="15" cy="12" r="2" fill="black" />
184+
<circle cx="9" cy="18" r="2" fill="black" />
185+
<circle cx="15" cy="18" r="2" fill="black" />
186+
</svg>
187+
</ng-container>
188+
<ng-container *ngTemplateOutlet="contentHeaderTemplate; context: { $implicit: column }"> </ng-container>
189+
</div>
190+
</th>
191+
</ng-template>
192+
<ng-template #tableDefaultThDefault>
193+
<th
194+
*ngFor="let column of mainColumns; let i = index; trackBy: trackBy"
195+
class="po-table-header-ellipsis"
196+
[style.width]="column.width"
197+
[style.max-width]="column.width"
198+
[style.min-width]="column.width"
199+
[attr.data-po-table-column-name]="column.label || (column.property | titlecase) | lowercase"
200+
[class.po-clickable]="(sort && column.sortable !== false) || hasService"
201+
[ngClass]="{
202+
'po-table-header-sorted':
203+
sort &&
204+
JSON.stringify(sortedColumn?.property) === JSON.stringify(column) &&
205+
(sortedColumn.ascending || !sortedColumn.ascending)
206+
}"
207+
[class.po-table-header-subtitle]="column.type === 'subtitle'"
208+
(click)="sortColumn(column)"
209+
>
210+
<div
211+
class="po-table-header-flex"
212+
[class.po-table-header-fixed-inner]="height"
213+
[class.po-table-header-flex-right]="column.type === 'currency' || column.type === 'number'"
214+
[class.po-table-header-flex-center]="column.type === 'subtitle'"
215+
>
216+
<ng-container *ngTemplateOutlet="contentHeaderTemplate; context: { $implicit: column }"> </ng-container>
217+
</div>
218+
</th>
219+
</ng-template>
163220

164221
<th
165222
*ngIf="hasRowTemplateWithArrowDirectionRight && (hasVisibleActions || hideColumnsManager)"
@@ -373,7 +430,12 @@
373430
[ngStyle]="{ 'table-layout': !hasItems ? 'fixed' : 'auto' }"
374431
>
375432
<thead class="po-table-header-sticky" [style.top]="inverseOfTranslation">
376-
<tr [class.po-table-header]="!height">
433+
<tr
434+
[class.po-table-header]="!height"
435+
cdkDropList
436+
cdkDropListOrientation="horizontal"
437+
(cdkDropListDropped)="drop($event)"
438+
>
377439
<th
378440
*ngIf="hasSelectableColumn"
379441
[style.pointer-events]="hideSelectAll ? 'none' : 'auto'"
@@ -406,33 +468,87 @@
406468
<ng-container *ngIf="height; then noColumnsWithHeight; else noColumnsWithoutHeight"> </ng-container>
407469
</th>
408470

409-
<th
410-
*ngFor="let column of mainColumns; let i = index; trackBy: trackBy"
411-
class="po-table-header-ellipsis"
412-
[style.width]="column.width"
413-
[style.max-width]="column.width"
414-
[style.min-width]="column.width"
415-
[attr.data-po-table-column-name]="column.label || (column.property | titlecase) | lowercase"
416-
[class.po-clickable]="(sort && column.sortable !== false) || hasService"
417-
[ngClass]="{
418-
'po-table-header-sorted':
419-
sort &&
420-
JSON.stringify(sortedColumn?.property) === JSON.stringify(column) &&
421-
(sortedColumn.ascending || !sortedColumn.ascending)
422-
}"
423-
[ngStyle]="{ 'width': !hasItems ? '100%' : 'auto' }"
424-
[class.po-table-header-subtitle]="column.type === 'subtitle'"
425-
(click)="sortColumn(column)"
426-
>
427-
<div
428-
class="po-table-header-flex"
429-
[class.po-table-header-fixed-inner]="height"
430-
[class.po-table-header-flex-right]="column.type === 'currency' || column.type === 'number'"
431-
[class.po-table-header-flex-center]="column.type === 'subtitle'"
471+
<ng-container *ngIf="this.isDraggable; then tableVirtualScrollThDragDrop; else tableVirtualScrollThDefault">
472+
</ng-container>
473+
<ng-template #tableVirtualScrollThDragDrop>
474+
<th
475+
*ngFor="let column of mainColumns; let i = index; trackBy: trackBy"
476+
class="po-table-header-ellipsis"
477+
[style.width]="column.width"
478+
[style.max-width]="column.width"
479+
[style.min-width]="column.width"
480+
[attr.data-po-table-column-name]="column.label || (column.property | titlecase) | lowercase"
481+
[class.po-clickable]="(sort && column.sortable !== false) || hasService"
482+
[ngClass]="{
483+
'po-table-header-sorted':
484+
sort &&
485+
JSON.stringify(sortedColumn?.property) === JSON.stringify(column) &&
486+
(sortedColumn.ascending || !sortedColumn.ascending)
487+
}"
488+
[ngStyle]="{ 'width': !hasItems ? '100%' : 'auto' }"
489+
[class.po-table-header-subtitle]="column.type === 'subtitle'"
490+
[class.po-table-column-drag-box]="this.isDraggable"
491+
(click)="sortColumn(column)"
492+
cdkDrag
493+
cdkDragLockAxis="x"
432494
>
433-
<ng-container *ngTemplateOutlet="contentHeaderTemplate; context: { $implicit: column }"> </ng-container>
434-
</div>
435-
</th>
495+
<div
496+
class="po-table-header-flex"
497+
[class.po-table-header-fixed-inner]="height"
498+
[class.po-table-header-flex-right]="column.type === 'currency' || column.type === 'number'"
499+
[class.po-table-header-flex-center]="column.type === 'subtitle'"
500+
>
501+
<ng-container *ngIf="this.isDraggable">
502+
<svg
503+
cdkDragHandle
504+
width="24"
505+
height="24"
506+
viewBox="0 0 24 24"
507+
fill="none"
508+
xmlns="http://www.w3.org/2000/svg"
509+
>
510+
<circle cx="9" cy="6" r="2" fill="black" />
511+
<circle cx="15" cy="6" r="2" fill="black" />
512+
<circle cx="9" cy="12" r="2" fill="black" />
513+
<circle cx="15" cy="12" r="2" fill="black" />
514+
<circle cx="9" cy="18" r="2" fill="black" />
515+
<circle cx="15" cy="18" r="2" fill="black" />
516+
</svg>
517+
</ng-container>
518+
519+
<ng-container *ngTemplateOutlet="contentHeaderTemplate; context: { $implicit: column }"> </ng-container>
520+
</div>
521+
</th>
522+
</ng-template>
523+
<ng-template #tableVirtualScrollThDefault>
524+
<th
525+
*ngFor="let column of mainColumns; let i = index; trackBy: trackBy"
526+
class="po-table-header-ellipsis"
527+
[style.width]="column.width"
528+
[style.max-width]="column.width"
529+
[style.min-width]="column.width"
530+
[attr.data-po-table-column-name]="column.label || (column.property | titlecase) | lowercase"
531+
[class.po-clickable]="(sort && column.sortable !== false) || hasService"
532+
[ngClass]="{
533+
'po-table-header-sorted':
534+
sort &&
535+
JSON.stringify(sortedColumn?.property) === JSON.stringify(column) &&
536+
(sortedColumn.ascending || !sortedColumn.ascending)
537+
}"
538+
[ngStyle]="{ 'width': !hasItems ? '100%' : 'auto' }"
539+
[class.po-table-header-subtitle]="column.type === 'subtitle'"
540+
(click)="sortColumn(column)"
541+
>
542+
<div
543+
class="po-table-header-flex"
544+
[class.po-table-header-fixed-inner]="height"
545+
[class.po-table-header-flex-right]="column.type === 'currency' || column.type === 'number'"
546+
[class.po-table-header-flex-center]="column.type === 'subtitle'"
547+
>
548+
<ng-container *ngTemplateOutlet="contentHeaderTemplate; context: { $implicit: column }"> </ng-container>
549+
</div>
550+
</th>
551+
</ng-template>
436552

437553
<th
438554
*ngIf="hasRowTemplateWithArrowDirectionRight && (hasVisibleActions || hideColumnsManager)"

0 commit comments

Comments
 (0)