Skip to content

Commit bd3f27e

Browse files
dafodamyanpetev
authored andcommitted
feat(row-drag): Adding igxDragCustomGhost directive
1 parent a746a94 commit bd3f27e

File tree

11 files changed

+274
-13
lines changed

11 files changed

+274
-13
lines changed

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ All notable changes for each version of this project will be documented in this
3030
- `setOffset` method added. It offsets the content along the corresponding axis by the provided amount.
3131
- `IgxToggleDirective`:
3232
- `setOffset` method added. It offsets the content along the corresponding axis by the provided amount.
33+
- `IgxRowDragGhost` directive is added. It allows providing a custom template for the drag ghost when dragging a row.
34+
```html
35+
<igx-grid #grid1 [data]="remote | async" primaryKey="ProductID"
36+
[rowDraggable]="true">
37+
<igx-column field="ProductName"></igx-column>
38+
<igx-column field="ProductID"></igx-column>
39+
<igx-column field="UnitsInStock"></igx-column>
40+
<ng-template let-data igxRowDragGhost>
41+
<div>
42+
Moving {{data.ProductName}}!
43+
</div>
44+
</ng-template>
45+
</igx-grid>
46+
```
3347

3448
## 8.2.6
3549

projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ export class IgxDragLocation {
151151
})
152152
export class IgxDragDirective implements AfterContentInit, OnDestroy {
153153

154+
protected ghostContext: any = null;
155+
154156
/**
155157
* - Save data inside the `igxDrag` directive. This can be set when instancing `igxDrag` on an element.
156158
* ```html
@@ -1099,7 +1101,7 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
10991101

11001102
let dynamicGhostRef;
11011103
if (this.ghostTemplate) {
1102-
dynamicGhostRef = this.viewContainer.createEmbeddedView(this.ghostTemplate);
1104+
dynamicGhostRef = this.viewContainer.createEmbeddedView(this.ghostTemplate, this.ghostContext);
11031105
this.ghostElement = dynamicGhostRef.rootNodes[0];
11041106
} else {
11051107
this.ghostElement = node ? node.cloneNode(true) : this.element.nativeElement.cloneNode(true);

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

+20
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ import { IgxGridToolbarCustomContentDirective } from './toolbar/toolbar.directiv
132132
import { IgxColumnComponent } from './columns/column.component';
133133
import { IgxColumnGroupComponent } from './columns/column-group.component';
134134
import { IGridSortingStrategy } from '../data-operations/sorting-strategy';
135+
import { IgxRowDragGhostDirective } from './row-drag.directive';
135136

136137
const MINIMUM_COLUMN_WIDTH = 136;
137138
const FILTER_ROW_HEIGHT = 50;
@@ -1912,6 +1913,13 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
19121913
@ContentChildren(IgxRowSelectorDirective, { read: IgxRowSelectorDirective, descendants: false })
19131914
public rowSelectorsTemplates: QueryList<IgxRowSelectorDirective>;
19141915

1916+
/**
1917+
* @hidden
1918+
* @internal
1919+
*/
1920+
@ContentChildren(IgxRowDragGhostDirective, { read: TemplateRef, descendants: false })
1921+
public dragGhostCustomTemplates: QueryList<TemplateRef<any>>;
1922+
19151923
/**
19161924
* @hidden
19171925
*/
@@ -3167,6 +3175,18 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
31673175
}
31683176
}
31693177

3178+
/**
3179+
* @hidden
3180+
* @internal
3181+
*/
3182+
public getDragGhostCustomTemplate() {
3183+
if (this.dragGhostCustomTemplates && this.dragGhostCustomTemplates.first) {
3184+
return this.dragGhostCustomTemplates.first;
3185+
}
3186+
3187+
return null;
3188+
}
3189+
31703190
/**
31713191
* @hidden
31723192
*/

projects/igniteui-angular/src/lib/grids/grid/grid-row.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div class="igx-grid__row-indentation igx-grid__row-indentation--level-{{grid.groupingExpressions.length}}"></div>
33
</ng-container>
44
<ng-container *ngIf="rowDraggable">
5-
<div [class]="resolveDragIndicatorClasses" [igxRowDrag]="this" (click)="$event.stopPropagation()">
5+
<div [class]="resolveDragIndicatorClasses" [igxRowDrag]="this" (click)="$event.stopPropagation()" [ghostTemplate]="this.grid.getDragGhostCustomTemplate()">
66
<ng-container *ngTemplateOutlet="this.grid.dragIndicatorIconTemplate ? this.grid.dragIndicatorIconTemplate : this.grid.dragIndicatorIconBase"></ng-container>
77
</div>
88
</ng-container>

projects/igniteui-angular/src/lib/grids/grid/row-drag.directive.spec.ts

+184-4
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ describe('IgxGrid - Row Drag Tests #grid', () => {
4444
TestBed.configureTestingModule({
4545
declarations: [
4646
IgxGridRowDraggableComponent,
47+
IgxGridRowCustomGhostDraggableComponent,
4748
IgxGridFeaturesRowDragComponent,
4849
IgxHierarchicalGridTestComponent,
50+
IgxHierarchicalGridCustomGhostTestComponent,
4951
IgxTreeGridTestComponent
5052
],
5153
imports: [
@@ -384,6 +386,33 @@ describe('IgxGrid - Row Drag Tests #grid', () => {
384386
const ghostElements = document.getElementsByClassName(CSS_CLASS_GHOST_ROW);
385387
expect(ghostElements.length).toEqual(0);
386388
}));
389+
390+
it('should correctly create custom ghost element', (async () => {
391+
fixture = TestBed.createComponent(IgxGridRowCustomGhostDraggableComponent);
392+
grid = fixture.componentInstance.instance;
393+
fixture.detectChanges();
394+
dragIndicatorElements = fixture.debugElement.queryAll(By.css('.' + CSS_CLASS_DRAG_INDICATOR));
395+
dragRows = fixture.debugElement.queryAll(By.directive(IgxRowDragDirective));
396+
const rowDragDirective = dragRows[1].injector.get(IgxRowDragDirective) as any;
397+
const dragIndicatorElement = dragIndicatorElements[2].nativeElement;
398+
const startPoint: Point = UIInteractions.getPointFromElement(dragIndicatorElement);
399+
const movePoint: Point = UIInteractions.getPointFromElement(rows[4].nativeElement);
400+
const dropPoint: Point = UIInteractions.getPointFromElement(dropAreaElement);
401+
let ghostElements: HTMLCollection;
402+
403+
await pointerDown(dragIndicatorElement, startPoint, fixture);
404+
await pointerMove(dragIndicatorElement, movePoint, fixture);
405+
await pointerMove(dragIndicatorElement, dropPoint, fixture);
406+
ghostElements = document.getElementsByClassName(CSS_CLASS_GHOST_ROW);
407+
expect(ghostElements.length).toEqual(1);
408+
409+
expect(rowDragDirective.ghostContext.data.ProductName).toEqual('NetAdvantage');
410+
expect(rowDragDirective.ghostContext.data.ID).toEqual(2);
411+
expect(rowDragDirective.ghostContext.grid).toEqual(grid);
412+
413+
const ghostText = document.getElementsByClassName(CSS_CLASS_GHOST_ROW)[0].textContent;
414+
expect(ghostText).toEqual(' Moving a row! ');
415+
}));
387416
});
388417
describe('Grid Features Integration Tests', () => {
389418
let dragGrid: IgxGridComponent;
@@ -635,8 +664,8 @@ describe('IgxGrid - Row Drag Tests #grid', () => {
635664
expect(row.grid.rowDragging).toBeTruthy();
636665

637666
const ghostElements = document.getElementsByClassName(CSS_CLASS_GHOST_ROW);
638-
const ghostElement = ghostElements[0];
639-
expect(ghostElements.length).toEqual(1);
667+
const ghostElement = ghostElements[1];
668+
expect(ghostElements.length).toEqual(2);
640669
expect(ghostElement.classList.contains(CSS_CLASS_SELECTED_ROW)).toBeFalsy();
641670

642671
await pointerMove(dragIndicatorElement, dropPoint, fixture);
@@ -787,7 +816,7 @@ describe('IgxGrid - Row Drag Tests #grid', () => {
787816
dragRows = fixture.debugElement.queryAll(By.directive(IgxRowDragDirective));
788817
}));
789818

790-
it('should be able to drag row on every hiearchical level', (async () => {
819+
it('should be able to drag row on every hierarchical level', (async () => {
791820
// first level row
792821
let dragIndicatorElement: Element = dragIndicatorElements[1].nativeElement;
793822
let rowToDrag = dragGrid.getRowByIndex(0);
@@ -841,6 +870,47 @@ describe('IgxGrid - Row Drag Tests #grid', () => {
841870
await pointerUp(dragIndicatorElement, dropPoint, fixture);
842871
verifyRowDragEndEvent(nestedChildGrid, rowToDrag, rowDragDirective, false, 1);
843872
}));
873+
874+
it('should correctly create custom ghost element', (async () => {
875+
fixture = TestBed.createComponent(IgxHierarchicalGridCustomGhostTestComponent );
876+
dragGrid = fixture.componentInstance.hDragGrid;
877+
fixture.detectChanges();
878+
dragIndicatorElements = fixture.debugElement.queryAll(By.css('.' + CSS_CLASS_DRAG_INDICATOR));
879+
dragRows = fixture.debugElement.queryAll(By.directive(IgxRowDragDirective));
880+
881+
// first level row
882+
let dragIndicatorElement: Element = dragIndicatorElements[1].nativeElement;
883+
let rowToDrag = dragGrid.getRowByIndex(0);
884+
let rowDragDirective = dragRows[0].injector.get(IgxRowDragDirective) as any;
885+
886+
let startPoint: Point = UIInteractions.getPointFromElement(dragIndicatorElement);
887+
const movePoint: Point = UIInteractions.getPointFromElement(dragGrid.getRowByIndex(3).nativeElement);
888+
const dropPoint: Point = UIInteractions.getPointFromElement(dropAreaElement);
889+
890+
await pointerDown(dragIndicatorElement, startPoint, fixture);
891+
await pointerMove(dragIndicatorElement, movePoint, fixture);
892+
await pointerMove(dragIndicatorElement, dropPoint, fixture);
893+
await pointerUp(dragIndicatorElement, dropPoint, fixture);
894+
895+
expect(rowDragDirective.ghostContext.data.ProductName).toEqual('Product: A0');
896+
expect(rowDragDirective.ghostContext.grid).toEqual(dragGrid);
897+
898+
// second level row
899+
dragIndicatorElement = dragIndicatorElements[8].nativeElement;
900+
const childGrid = dragGrid.hgridAPI.getChildGrids(false)[0];
901+
rowToDrag = childGrid.getRowByIndex(0);
902+
rowDragDirective = dragRows[4].injector.get(IgxRowDragDirective);
903+
startPoint = UIInteractions.getPointFromElement(dragIndicatorElement);
904+
905+
await pointerDown(dragIndicatorElement, startPoint, fixture);
906+
await pointerMove(dragIndicatorElement, movePoint, fixture);
907+
await pointerMove(dragIndicatorElement, dropPoint, fixture);
908+
await pointerUp(dragIndicatorElement, dropPoint, fixture);
909+
910+
expect(rowDragDirective.ghostContext.data.ProductName).toEqual('Product: A0');
911+
expect(rowDragDirective.ghostContext.data.ChildLevels).toEqual(2);
912+
expect(rowDragDirective.ghostContext.grid).toEqual(childGrid);
913+
}));
844914
});
845915
describe('Tree Grid Tests', () => {
846916
let dragGrid: IgxTreeGridComponent;
@@ -857,7 +927,7 @@ describe('IgxGrid - Row Drag Tests #grid', () => {
857927
dragRows = fixture.debugElement.queryAll(By.directive(IgxRowDragDirective));
858928
}));
859929

860-
it('should be able to drag row on every hiearchical level', (async () => {
930+
it('should be able to drag row on every hierarchical level', (async () => {
861931
// first level row
862932
let dragIndicatorElement: Element = dragIndicatorElements[1].nativeElement;
863933
let rowToDrag = dragGrid.getRowByIndex(0);
@@ -960,6 +1030,65 @@ export class IgxGridRowDraggableComponent extends DataParent {
9601030
}
9611031
}
9621032

1033+
@Component({
1034+
template: `
1035+
<igx-grid #grid
1036+
[width]='width'
1037+
[height]='height'
1038+
primaryKey="ID"
1039+
[data]="data"
1040+
[autoGenerate]="true" (onColumnInit)="columnsCreated($event)" (onGroupingDone)="onGroupingDoneHandler($event)"
1041+
[rowEditable]="true" [rowDraggable]="enableRowDraggable"
1042+
>
1043+
<ng-template let-data igxRowDragGhost>
1044+
<div class="dragGhost">
1045+
<igx-icon fontSet="material"></igx-icon>
1046+
Moving a row!
1047+
</div>
1048+
</ng-template>
1049+
</igx-grid>
1050+
<div #dropArea class="droppable-area" igxDrop (dropped)="onRowDrop($event)"
1051+
[ngStyle]="{width:'100px', height:'100px', backgroundColor:'red'}">
1052+
</div>
1053+
<div #nonDroppableArea class="non-droppable-area"
1054+
[ngStyle]="{width:'100px', height:'100px', backgroundColor:'yellow'}">
1055+
</div>
1056+
`
1057+
})
1058+
export class IgxGridRowCustomGhostDraggableComponent extends DataParent {
1059+
public width = '800px';
1060+
public height = null;
1061+
1062+
@ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true })
1063+
public instance: IgxGridComponent;
1064+
1065+
@ViewChild('dropArea', { read: IgxDropDirective, static: true })
1066+
public dropArea: IgxDropDirective;
1067+
1068+
public enableSorting = false;
1069+
public enableFiltering = false;
1070+
public enableResizing = false;
1071+
public enableEditing = true;
1072+
public enableGrouping = true;
1073+
public enableRowEditing = true;
1074+
public enableRowDraggable = true;
1075+
public currentSortExpressions;
1076+
1077+
public columnsCreated(column: IgxColumnComponent) {
1078+
column.sortable = this.enableSorting;
1079+
column.filterable = this.enableFiltering;
1080+
column.resizable = this.enableResizing;
1081+
column.editable = this.enableEditing;
1082+
column.groupable = this.enableGrouping;
1083+
}
1084+
public onGroupingDoneHandler(sortExpr) {
1085+
this.currentSortExpressions = sortExpr;
1086+
}
1087+
public onRowDrop(args) {
1088+
args.cancel = true;
1089+
}
1090+
}
1091+
9631092
@Component({
9641093
template: `
9651094
<igx-grid #dragGrid
@@ -1056,6 +1185,57 @@ export class IgxHierarchicalGridTestComponent {
10561185
}
10571186
}
10581187

1188+
@Component({
1189+
template: `
1190+
<igx-hierarchical-grid #hierarchicalDragGrid [data]="data"
1191+
[autoGenerate]="true" [height]="'500px'" [width]="'1500px'"
1192+
primaryKey="ID" [expandChildren]='true' [rowDraggable]="true">
1193+
<igx-row-island [key]="'childData'" [expandChildren]='true' [autoGenerate]="true" [rowDraggable]="true" #rowIsland>
1194+
<igx-row-island [key]="'childData2'" [autoGenerate]="true" [rowDraggable]="true" #rowIsland2 >
1195+
</igx-row-island>
1196+
<ng-template let-data igxRowDragGhost>
1197+
<div>
1198+
Moving {{data.ProductName}}!
1199+
</div>
1200+
</ng-template>
1201+
</igx-row-island>
1202+
<ng-template let-data igxRowDragGhost>
1203+
<div>
1204+
Moving {{data.ProductName}}!
1205+
</div>
1206+
</ng-template>
1207+
</igx-hierarchical-grid>`
1208+
})
1209+
export class IgxHierarchicalGridCustomGhostTestComponent {
1210+
public data;
1211+
newData = [];
1212+
@ViewChild('hierarchicalDragGrid', { read: IgxHierarchicalGridComponent, static: true }) public hDragGrid: IgxHierarchicalGridComponent;
1213+
@ViewChild('rowIsland', { read: IgxRowIslandComponent, static: true }) public rowIsland: IgxRowIslandComponent;
1214+
@ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) public rowIsland2: IgxRowIslandComponent;
1215+
1216+
constructor() {
1217+
this.data = this.generateData(2, 3);
1218+
}
1219+
generateData(count: number, level: number) {
1220+
const prods = [];
1221+
const currLevel = level;
1222+
let children;
1223+
for (let i = 0; i < count; i++) {
1224+
const item = {
1225+
ID: i, ChildLevels: currLevel, ProductName: 'Product: A' + i, 'Col1': i,
1226+
'Col2': i, 'Col3': i
1227+
};
1228+
if (currLevel > 1) {
1229+
children = this.generateData(count / 2, currLevel - 1);
1230+
const childProp = currLevel === 3 ? 'childData' : 'childData2';
1231+
item[childProp] = children;
1232+
}
1233+
prods.push(item);
1234+
}
1235+
return prods;
1236+
}
1237+
}
1238+
10591239
@Component({
10601240
template: `
10611241
<igx-tree-grid #treeGrid [data]="data" primaryKey="employeeID" foreignKey="PID" width="900px" height="500px" [rowDraggable]="true">

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts

+11
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,17 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti
663663
}
664664
}
665665

666+
/**
667+
* @hidden
668+
* @internal
669+
*/
670+
public getDragGhostCustomTemplate(): TemplateRef<any> {
671+
if (this.parentIsland) {
672+
return this.parentIsland.getDragGhostCustomTemplate();
673+
}
674+
return super.getDragGhostCustomTemplate();
675+
}
676+
666677
/**
667678
* @hidden
668679
*/

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</ng-template>
1616

1717
<ng-container *ngIf="rowDraggable">
18-
<div [class]="resolveDragIndicatorClasses" [igxRowDrag]="this" (click)="$event.stopPropagation()">
18+
<div [class]="resolveDragIndicatorClasses" [igxRowDrag]="this" (click)="$event.stopPropagation()" [ghostTemplate]="this.grid.getDragGhostCustomTemplate()">
1919
<ng-container *ngTemplateOutlet="this.grid.dragIndicatorIconTemplate ? this.grid.dragIndicatorIconTemplate : this.grid.dragIndicatorIconBase"></ng-container>
2020
</div>
2121
</ng-container>

0 commit comments

Comments
 (0)