Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Angular wrapper example improvement (#1824)
* Angular component wrapper
- Loading branch information
1 parent
3c1db44
commit 21167d3
Showing
8 changed files
with
373 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<div class="grid-stack-item-content"> | ||
<ng-content></ng-content> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
:host { | ||
display: block; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {ChangeDetectionStrategy, Component, ElementRef, Input, NgZone, OnInit, Renderer2} from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'ef-gridstack-item', | ||
templateUrl: './gridstack-item.component.html', | ||
styleUrls: ['./gridstack-item.component.scss'], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export class GridstackItemComponent implements OnInit { | ||
|
||
@Input() public x: number; | ||
@Input() public y: number; | ||
@Input() public width: number; | ||
@Input() public height: number; | ||
@Input() public minW: number; | ||
@Input() public minH: number; | ||
@Input() public identifier: string; | ||
|
||
constructor( | ||
private readonly ngZone: NgZone, | ||
private readonly _elementRef: ElementRef<HTMLElement>, | ||
private readonly renderer2: Renderer2, | ||
) { | ||
} | ||
|
||
get elementRef(): ElementRef<HTMLElement> { | ||
return this._elementRef; | ||
} | ||
|
||
public ngOnInit(): void { | ||
this.renderer2.addClass(this._elementRef.nativeElement, 'grid-stack-item'); | ||
} | ||
|
||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
@use "sass:math"; | ||
|
||
$gridstack-max-columns: 24; | ||
|
||
:host { | ||
display: block; | ||
} | ||
|
||
::ng-deep { | ||
@mixin gen-grid-stack-item-width($gridstack-columns) { | ||
.grid-stack-#{$gridstack-columns} { | ||
.grid-stack-item { | ||
@for $i from 1 through $gridstack-columns { | ||
&[gs-w='#{$i}'] { | ||
width: math.div(100% , $gridstack-columns) * $i; | ||
} | ||
&[gs-x='#{$i}'] { | ||
left: math.div(100% , $gridstack-columns) * $i; | ||
} | ||
&[gs-min-w='#{$i}'] { | ||
min-width: math.div(100% , $gridstack-columns) * $i; | ||
} | ||
&[gs-max-w='#{$i}'] { | ||
max-width: math.div(100% ,$gridstack-columns) * $i; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@for $i from 1 through $gridstack-max-columns { | ||
@include gen-grid-stack-item-width($i); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,279 @@ | ||
import { | ||
ChangeDetectionStrategy, | ||
Component, | ||
ContentChildren, | ||
ElementRef, | ||
EventEmitter, | ||
Input, | ||
NgZone, | ||
OnDestroy, | ||
OnInit, | ||
Output, | ||
QueryList, | ||
Renderer2, | ||
} from '@angular/core'; | ||
import {GridstackItemComponent} from './gridstack-item.component'; | ||
import {merge, Subject} from 'rxjs'; | ||
import {GridStack, GridStackEvent, GridStackOptions} from 'gridstack'; | ||
import 'gridstack/dist/h5/gridstack-dd-native'; | ||
import {map, takeUntil} from 'rxjs/operators'; | ||
|
||
@Component({ | ||
selector: 'ef-gridstack', | ||
templateUrl: './gridstack.component.html', | ||
styleUrls: ['./gridstack.component.scss'], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export class GridstackComponent implements OnInit, OnDestroy { | ||
|
||
@ContentChildren(GridstackItemComponent) public gridstackItems: QueryList<GridstackItemComponent>; | ||
|
||
@Input() public options: GridStackOptions; | ||
|
||
@Output() public gridstackAdded = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackChange = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackDisable = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackDrag = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackDragStart = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackDragStop = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackDropped = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackEnable = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackRemoved = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackResize = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackResizeStart = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
@Output() public gridstackResizeStop = new EventEmitter<{ | ||
event: GridStackEvent; | ||
grid: GridStack; | ||
}>(); | ||
|
||
private readonly update$ = new Subject<void>(); | ||
private readonly destroy$ = new Subject<boolean>(); | ||
private _grid: GridStack; | ||
|
||
constructor( | ||
private readonly ngZone: NgZone, | ||
private readonly elementRef: ElementRef<HTMLElement>, | ||
private readonly renderer2: Renderer2, | ||
) { | ||
} | ||
|
||
get grid(): GridStack { | ||
return this._grid; | ||
} | ||
|
||
public ngOnInit(): void { | ||
this.renderer2.addClass(this.elementRef.nativeElement, 'grid-stack'); | ||
} | ||
|
||
public ngAfterContentInit(): void { | ||
this.ngZone.runOutsideAngular(() => { | ||
this._grid = GridStack.init(this.options, this.elementRef.nativeElement); | ||
this.hookEvents(this._grid); | ||
merge( | ||
this.update$, | ||
this.gridstackItems.changes, | ||
).pipe( | ||
map(() => this.gridstackItems.toArray()), | ||
takeUntil(this.destroy$), | ||
).subscribe(items => { | ||
const gridItems = this._grid.getGridItems(); | ||
let elementsToRemove = [...gridItems]; | ||
this._grid.batchUpdate(); | ||
this._grid.column(this.options.column); | ||
for (const item of items) { | ||
const existingItem = gridItems.find(x => x.gridstackNode.id === item.identifier); | ||
if (existingItem) { | ||
elementsToRemove = elementsToRemove.filter(x => x.gridstackNode.id !== item.identifier); | ||
this._grid.update(existingItem, { | ||
h: item.height, | ||
w: item.width, | ||
x: item.x, | ||
y: item.y, | ||
}); | ||
} else { | ||
this._grid.addWidget(item.elementRef.nativeElement, { | ||
id: item.identifier, | ||
h: item.height, | ||
w: item.width, | ||
x: item.x, | ||
y: item.y, | ||
minW: item.minW, | ||
minH: item.minH, | ||
}); | ||
} | ||
} | ||
for (const gridItemHTMLElement of elementsToRemove) { | ||
this._grid.removeWidget(gridItemHTMLElement); | ||
} | ||
this._grid.commit(); | ||
}); | ||
this.update$.next(); | ||
}); | ||
} | ||
|
||
public ngOnDestroy(): void { | ||
this.destroy$.next(true); | ||
this.destroy$.complete(); | ||
this.update$.complete(); | ||
this._grid.destroy(); | ||
} | ||
|
||
update() { | ||
this.update$.next(); | ||
} | ||
|
||
private hookEvents(grid: GridStack) { | ||
grid.on('added', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackAdded.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('disable', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackDisable.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('enable', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackEnable.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('removed', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackRemoved.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('dropped', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackDropped.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('resize', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackResize.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('resizestart', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackResizeStart.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('resizestop', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackResizeStop.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('drag', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackDrag.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('dragstart', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackDragStart.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('dragstop', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackDragStop.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
|
||
grid.on('change', event => { | ||
this.ngZone.run(() => { | ||
this.gridstackChange.emit({ | ||
event: event as unknown as GridStackEvent, | ||
grid, | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import {NgModule} from '@angular/core'; | ||
import {CommonModule} from '@angular/common'; | ||
import {GridstackComponent} from './gridstack.component'; | ||
import {GridstackItemComponent} from './gridstack-item.component'; | ||
|
||
@NgModule({ | ||
declarations: [ | ||
GridstackComponent, | ||
GridstackItemComponent, | ||
], | ||
exports: [ | ||
GridstackComponent, | ||
GridstackItemComponent, | ||
], | ||
imports: [ | ||
CommonModule, | ||
], | ||
}) | ||
export class GridstackModule { | ||
} |