Skip to content

Commit

Permalink
Angular wrapper example improvement (#1824)
Browse files Browse the repository at this point in the history
* Angular component wrapper
  • Loading branch information
lacroixdavid1 committed Dec 28, 2022
1 parent 3c1db44 commit 21167d3
Show file tree
Hide file tree
Showing 8 changed files with 373 additions and 0 deletions.
1 change: 1 addition & 0 deletions demo/angular/README.md
Expand Up @@ -25,3 +25,4 @@ Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To u
## Further help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

3 changes: 3 additions & 0 deletions demo/angular/gridstack-item.component.html
@@ -0,0 +1,3 @@
<div class="grid-stack-item-content">
<ng-content></ng-content>
</div>
3 changes: 3 additions & 0 deletions demo/angular/gridstack-item.component.scss
@@ -0,0 +1,3 @@
:host {
display: block;
}
34 changes: 34 additions & 0 deletions demo/angular/gridstack-item.component.ts
@@ -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.
33 changes: 33 additions & 0 deletions demo/angular/gridstack.component.scss
@@ -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);
}
}
279 changes: 279 additions & 0 deletions demo/angular/gridstack.component.ts
@@ -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,
});
});
});
}

}
20 changes: 20 additions & 0 deletions demo/angular/gridstack.module.ts
@@ -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 {
}

0 comments on commit 21167d3

Please sign in to comment.