gridstack 10.1.2 → 10.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/angular/angular.json +3 -0
  2. package/angular/package.json +1 -1
  3. package/dist/angular/esm2020/gridstack-angular.mjs +4 -4
  4. package/dist/angular/esm2020/lib/base-widget.mjs +30 -30
  5. package/dist/angular/esm2020/lib/gridstack-item.component.mjs +52 -52
  6. package/dist/angular/esm2020/lib/gridstack.component.mjs +266 -264
  7. package/dist/angular/esm2020/lib/gridstack.module.mjs +39 -39
  8. package/dist/angular/esm2020/public-api.mjs +7 -7
  9. package/dist/angular/fesm2015/gridstack-angular.mjs +368 -366
  10. package/dist/angular/fesm2015/gridstack-angular.mjs.map +1 -1
  11. package/dist/angular/fesm2020/gridstack-angular.mjs +363 -361
  12. package/dist/angular/fesm2020/gridstack-angular.mjs.map +1 -1
  13. package/dist/angular/index.d.ts +5 -5
  14. package/dist/angular/lib/base-widget.d.ts +16 -16
  15. package/dist/angular/lib/gridstack-item.component.d.ts +37 -37
  16. package/dist/angular/lib/gridstack.component.d.ts +129 -129
  17. package/dist/angular/lib/gridstack.module.d.ts +10 -10
  18. package/dist/angular/public-api.d.ts +4 -4
  19. package/dist/dd-base-impl.d.ts +1 -1
  20. package/dist/dd-base-impl.js +1 -1
  21. package/dist/dd-base-impl.js.map +1 -1
  22. package/dist/dd-draggable.d.ts +4 -4
  23. package/dist/dd-draggable.js +63 -19
  24. package/dist/dd-draggable.js.map +1 -1
  25. package/dist/dd-droppable.d.ts +1 -1
  26. package/dist/dd-droppable.js +1 -1
  27. package/dist/dd-droppable.js.map +1 -1
  28. package/dist/dd-element.d.ts +1 -1
  29. package/dist/dd-element.js +1 -1
  30. package/dist/dd-element.js.map +1 -1
  31. package/dist/dd-gridstack.d.ts +1 -1
  32. package/dist/dd-gridstack.js +2 -2
  33. package/dist/dd-gridstack.js.map +1 -1
  34. package/dist/dd-manager.d.ts +1 -1
  35. package/dist/dd-manager.js +1 -1
  36. package/dist/dd-manager.js.map +1 -1
  37. package/dist/dd-resizable-handle.d.ts +4 -3
  38. package/dist/dd-resizable-handle.js +12 -1
  39. package/dist/dd-resizable-handle.js.map +1 -1
  40. package/dist/dd-resizable.d.ts +1 -1
  41. package/dist/dd-resizable.js +1 -1
  42. package/dist/dd-resizable.js.map +1 -1
  43. package/dist/dd-touch.d.ts +1 -1
  44. package/dist/dd-touch.js +1 -1
  45. package/dist/dd-touch.js.map +1 -1
  46. package/dist/es5/dd-base-impl.d.ts +1 -1
  47. package/dist/es5/dd-base-impl.js +1 -1
  48. package/dist/es5/dd-base-impl.js.map +1 -1
  49. package/dist/es5/dd-draggable.d.ts +4 -4
  50. package/dist/es5/dd-draggable.js +78 -21
  51. package/dist/es5/dd-draggable.js.map +1 -1
  52. package/dist/es5/dd-droppable.d.ts +1 -1
  53. package/dist/es5/dd-droppable.js +1 -1
  54. package/dist/es5/dd-droppable.js.map +1 -1
  55. package/dist/es5/dd-element.d.ts +1 -1
  56. package/dist/es5/dd-element.js +1 -1
  57. package/dist/es5/dd-element.js.map +1 -1
  58. package/dist/es5/dd-gridstack.d.ts +1 -1
  59. package/dist/es5/dd-gridstack.js +2 -2
  60. package/dist/es5/dd-gridstack.js.map +1 -1
  61. package/dist/es5/dd-manager.d.ts +1 -1
  62. package/dist/es5/dd-manager.js +1 -1
  63. package/dist/es5/dd-manager.js.map +1 -1
  64. package/dist/es5/dd-resizable-handle.d.ts +4 -3
  65. package/dist/es5/dd-resizable-handle.js +13 -1
  66. package/dist/es5/dd-resizable-handle.js.map +1 -1
  67. package/dist/es5/dd-resizable.d.ts +1 -1
  68. package/dist/es5/dd-resizable.js +1 -1
  69. package/dist/es5/dd-resizable.js.map +1 -1
  70. package/dist/es5/dd-touch.d.ts +1 -1
  71. package/dist/es5/dd-touch.js +1 -1
  72. package/dist/es5/dd-touch.js.map +1 -1
  73. package/dist/es5/gridstack-all.js +1 -1
  74. package/dist/es5/gridstack-all.js.LICENSE.txt +1 -1
  75. package/dist/es5/gridstack-all.js.map +1 -1
  76. package/dist/es5/gridstack-engine.d.ts +1 -1
  77. package/dist/es5/gridstack-engine.js +1 -1
  78. package/dist/es5/gridstack-engine.js.map +1 -1
  79. package/dist/es5/gridstack-poly.js +1 -1
  80. package/dist/es5/gridstack.d.ts +9 -3
  81. package/dist/es5/gridstack.js +61 -28
  82. package/dist/es5/gridstack.js.map +1 -1
  83. package/dist/es5/types.d.ts +8 -8
  84. package/dist/es5/types.js +1 -1
  85. package/dist/es5/types.js.map +1 -1
  86. package/dist/es5/utils.d.ts +6 -1
  87. package/dist/es5/utils.js +26 -10
  88. package/dist/es5/utils.js.map +1 -1
  89. package/dist/gridstack-all.js +1 -1
  90. package/dist/gridstack-all.js.LICENSE.txt +1 -1
  91. package/dist/gridstack-all.js.map +1 -1
  92. package/dist/gridstack-engine.d.ts +1 -1
  93. package/dist/gridstack-engine.js +1 -1
  94. package/dist/gridstack-engine.js.map +1 -1
  95. package/dist/gridstack.css +1 -1
  96. package/dist/gridstack.d.ts +9 -3
  97. package/dist/gridstack.js +56 -26
  98. package/dist/gridstack.js.map +1 -1
  99. package/dist/types.d.ts +8 -8
  100. package/dist/types.js +1 -1
  101. package/dist/types.js.map +1 -1
  102. package/dist/utils.d.ts +6 -1
  103. package/dist/utils.js +25 -10
  104. package/dist/utils.js.map +1 -1
  105. package/doc/CHANGES.md +15 -0
  106. package/doc/README.md +7 -1
  107. package/package.json +3 -2
  108. package/angular/.vscode/extensions.json +0 -4
  109. package/angular/.vscode/launch.json +0 -20
  110. package/angular/.vscode/tasks.json +0 -42
  111. package/angular/projects/demo/.browserslistrc +0 -16
  112. package/angular/projects/demo/src/app/app.component.css +0 -11
  113. package/angular/projects/demo/src/app/app.component.html +0 -110
  114. package/angular/projects/demo/src/app/app.component.spec.ts +0 -25
  115. package/angular/projects/demo/src/app/app.component.ts +0 -223
  116. package/angular/projects/demo/src/app/app.module.ts +0 -39
  117. package/angular/projects/demo/src/app/dummy.component.ts +0 -34
  118. package/angular/projects/demo/src/app/ngFor.ts +0 -131
  119. package/angular/projects/demo/src/app/ngFor_cmd.ts +0 -106
  120. package/angular/projects/demo/src/app/simple.ts +0 -46
  121. package/angular/projects/demo/src/assets/.gitkeep +0 -0
  122. package/angular/projects/demo/src/environments/environment.ts +0 -16
  123. package/angular/projects/demo/src/favicon.ico +0 -0
  124. package/angular/projects/demo/src/index.html +0 -13
  125. package/angular/projects/demo/src/main.ts +0 -12
  126. package/angular/projects/demo/src/polyfills.ts +0 -53
  127. package/angular/projects/demo/src/styles.css +0 -41
  128. package/angular/projects/demo/src/test.ts +0 -26
  129. package/angular/projects/demo/tsconfig.app.json +0 -15
  130. package/angular/projects/demo/tsconfig.spec.json +0 -18
  131. package/angular/projects/lib/src/lib/base-widget.ts +0 -28
  132. package/angular/projects/lib/src/lib/gridstack-item.component.ts +0 -78
  133. package/angular/projects/lib/src/lib/gridstack.component.ts +0 -287
  134. package/angular/projects/lib/src/lib/gridstack.module.ts +0 -32
  135. package/angular/projects/lib/src/public-api.ts +0 -8
  136. package/angular/projects/lib/src/test.ts +0 -27
  137. package/dist/angular/src/base-widget.ts +0 -28
  138. package/dist/angular/src/gridstack-item.component.ts +0 -78
  139. package/dist/angular/src/gridstack.component.ts +0 -287
  140. package/dist/angular/src/gridstack.module.ts +0 -32
  141. package/dist/src/gridstack-extra.scss +0 -25
  142. package/dist/src/gridstack.scss +0 -157
@@ -1,11 +0,0 @@
1
- .test-container {
2
- margin-top: 30px;
3
- }
4
- button.active {
5
- color: #fff;
6
- background-color: #007bff;
7
- }
8
-
9
- .text-container {
10
- display: flex;
11
- }
@@ -1,110 +0,0 @@
1
-
2
- <div class="button-container">
3
- <p class="pick-info">Pick a demo to load:</p>
4
- <button (click)="onShow(0)" [class.active]="show===0">Simple</button>
5
- <button (click)="onShow(1)" [class.active]="show===1">ngFor case</button>
6
- <button (click)="onShow(2)" [class.active]="show===2">ngFor custom command</button>
7
- <button (click)="onShow(3)" [class.active]="show===3">Component HTML template</button>
8
- <button (click)="onShow(4)" [class.active]="show===4">Component ngFor</button>
9
- <button (click)="onShow(5)" [class.active]="show===5">Component Dynamic</button>
10
- <button (click)="onShow(6)" [class.active]="show===6">Nested Grid</button>
11
- <button (click)="onShow(7)" [class.active]="show===7">Two Grids + sidebar</button>
12
- </div>
13
-
14
- <div class="test-container">
15
- <angular-simple-test *ngIf="show===0"></angular-simple-test>
16
- <angular-ng-for-test *ngIf="show===1"></angular-ng-for-test>
17
- <angular-ng-for-cmd-test *ngIf="show===2"></angular-ng-for-cmd-test>
18
-
19
- <div *ngIf="show===3">
20
- <p><b>COMPONENT template</b>: using DOM template to use components statically</p>
21
- <button (click)="add()">add item</button>
22
- <button (click)="delete()">remove item</button>
23
- <button (click)="modify()">modify item</button>
24
- <button (click)="newLayout()">new layout</button>
25
- <gridstack [options]="gridOptions" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
26
- <gridstack-item gs-x="1" gs-y="0">item 1</gridstack-item>
27
- <gridstack-item gs-x="3" gs-y="0" gs-w="2">item 2 wide</gridstack-item>
28
- </gridstack>
29
- </div>
30
-
31
- <div *ngIf="show===4">
32
- <p><b>COMPONENT ngFor</b>: Most complete example that uses Component wrapper for grid and gridItem</p>
33
- <button (click)="addNgFor()">add item</button>
34
- <button (click)="deleteNgFor()">remove item</button>
35
- <button (click)="modifyNgFor()">modify item</button>
36
- <button (click)="newLayoutNgFor()">new layout</button>
37
- <gridstack [options]="gridOptions" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
38
- <gridstack-item *ngFor="let n of items; trackBy: identify" [options]="n">
39
- </gridstack-item>
40
- </gridstack>
41
- </div>
42
-
43
- <div *ngIf="show===5">
44
- <p><b>COMPONENT dynamic</b>: Best example that uses Component wrapper and dynamic grid creation (drag between grids, from toolbar, etc...)</p>
45
- <button (click)="add()">add item</button>
46
- <button (click)="delete()">remove item</button>
47
- <button (click)="modify()">modify item</button>
48
- <button (click)="newLayout()">new layout</button>
49
- <button (click)="saveGrid()">Save</button>
50
- <button (click)="clearGrid()">Clear</button>
51
- <button (click)="loadGrid()">Load</button>
52
- <gridstack [options]="gridOptionsFull" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
53
- </gridstack>
54
- </div>
55
-
56
-
57
- <div *ngIf="show===6">
58
- <p><b>Nested Grid</b>: shows nested component grids, like nested.html demo but with Ng Components</p>
59
- <button (click)="add()">add item</button>
60
- <button (click)="delete()">remove item</button>
61
- <button (click)="modify()">modify item</button>
62
- <button (click)="newLayout()">new layout</button>
63
- <button (click)="saveGrid()">Save</button>
64
- <button (click)="clearGrid()">Clear</button>
65
- <button (click)="loadGrid()">Load</button>
66
- <!-- TODO: addGrid() in code for testing instead ? -->
67
- <gridstack [options]="nestedGridOptions" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
68
- <div empty-content>Add items here or reload the grid</div>
69
- </gridstack>
70
- </div>
71
-
72
- <div *ngIf="show===7">
73
- <p><b>two.html</b>: shows multiple grids and outside drag&drop</p>
74
- <div class="row">
75
- <div class="col-md-3">
76
- <div class="sidebar">
77
- <!-- will size to match content -->
78
- <div class="grid-stack-item">
79
- <div class="grid-stack-item-content">Drag me</div>
80
- </div>
81
- <!-- manually force a drop size of 2x1 -->
82
- <div class="grid-stack-item" gs-w="2" gs-h="1" gs-max-w="3">
83
- <div class="grid-stack-item-content">2x1, max=3</div>
84
- </div>
85
- </div>
86
- </div>
87
- <div class="col-md-9">
88
- <div class="trash" id="trash">
89
- </div>
90
- </div>
91
- </div>
92
- <div class="row" style="margin-top: 20px">
93
- <div class="col-md-6">
94
- <gridstack [options]="twoGridOpt1"></gridstack>
95
- </div>
96
- <div class="col-md-6">
97
- <gridstack [options]="twoGridOpt2"></gridstack>
98
- </div>
99
- </div>
100
- </div>
101
-
102
-
103
- <div class="grid-container"></div>
104
-
105
- <div class="text-container">
106
- <textarea #origTextArea cols="50" rows="50" readonly="readonly"></textarea>
107
- <textarea #textArea cols="50" rows="50" readonly="readonly"></textarea>
108
- </div>
109
-
110
- </div>
@@ -1,25 +0,0 @@
1
- import { TestBed } from '@angular/core/testing';
2
- import { AppComponent } from './app.component';
3
-
4
- describe('AppComponent', () => {
5
- beforeEach(async () => {
6
- await TestBed.configureTestingModule({
7
- declarations: [
8
- AppComponent
9
- ],
10
- }).compileComponents();
11
- });
12
-
13
- it('should create the app', () => {
14
- const fixture = TestBed.createComponent(AppComponent);
15
- const app = fixture.componentInstance;
16
- expect(app).toBeTruthy();
17
- });
18
-
19
- it('should have content', () => {
20
- const fixture = TestBed.createComponent(AppComponent);
21
- fixture.detectChanges();
22
- const compiled = fixture.nativeElement as HTMLElement;
23
- expect(compiled.querySelector('.pick-info')?.textContent).toContain('Pick a demo to load');
24
- });
25
- });
@@ -1,223 +0,0 @@
1
- import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
2
- import { GridStack, GridStackOptions, GridStackWidget } from 'gridstack';
3
- import { AngularSimpleComponent } from './simple';
4
- import { AngularNgForTestComponent } from './ngFor';
5
- import { AngularNgForCmdTestComponent } from './ngFor_cmd';
6
-
7
- // NOTE: local testing of file
8
- // import { GridstackComponent, NgGridStackOptions, NgGridStackWidget, elementCB, gsCreateNgComponents, nodesCB } from './gridstack.component';
9
- import { GridstackComponent, NgGridStackOptions, NgGridStackWidget, elementCB, gsCreateNgComponents, nodesCB } from 'gridstack/dist/angular';
10
-
11
- // unique ids sets for each item for correct ngFor updating
12
- let ids = 1;
13
- @Component({
14
- selector: 'app-root',
15
- templateUrl: './app.component.html',
16
- styleUrls: ['./app.component.css']
17
- })
18
- export class AppComponent implements OnInit {
19
-
20
- @ViewChild(AngularSimpleComponent) case0Comp?: AngularSimpleComponent;
21
- @ViewChild(AngularNgForTestComponent) case1Comp?: AngularNgForTestComponent;
22
- @ViewChild(AngularNgForCmdTestComponent) case2Comp?: AngularNgForCmdTestComponent;
23
- @ViewChild(GridstackComponent) gridComp?: GridstackComponent;
24
- @ViewChild('origTextArea', {static: true}) origTextEl?: ElementRef<HTMLTextAreaElement>;
25
- @ViewChild('textArea', {static: true}) textEl?: ElementRef<HTMLTextAreaElement>;
26
-
27
- // which sample to show
28
- public show = 5;
29
-
30
- /** sample grid options and items to load... */
31
- public items: GridStackWidget[] = [
32
- {x: 0, y: 0, minW: 2},
33
- {x: 1, y: 1},
34
- {x: 2, y: 2},
35
- ];
36
- public gridOptions: GridStackOptions = {
37
- margin: 5,
38
- // float: true,
39
- minRow: 1,
40
- cellHeight: 70,
41
- columnOpts: { breakpoints: [{w:768, c:1}] },
42
- }
43
- private sub0: NgGridStackWidget[] = [{x:0, y:0, selector:'app-a'}, {x:1, y:0, content:'plain html'}, {x:0, y:1, selector:'app-b'} ];
44
- public gridOptionsFull: NgGridStackOptions = {
45
- ...this.gridOptions,
46
- children: this.sub0,
47
- }
48
-
49
- // nested grid options
50
- private subOptions: GridStackOptions = {
51
- cellHeight: 50, // should be 50 - top/bottom
52
- column: 'auto', // size to match container. make sure to include gridstack-extra.min.css
53
- acceptWidgets: true, // will accept .grid-stack-item by default
54
- margin: 5,
55
- };
56
- private sub1: NgGridStackWidget[] = [ {x:0, y:0, selector:'app-a'}, {x:1, y:0, selector:'app-b'}, {x:2, y:0, selector:'app-c'}, {x:3, y:0}, {x:0, y:1}, {x:1, y:1}];
57
- private sub2: NgGridStackWidget[] = [ {x:0, y:0}, {x:0, y:1, w:2}];
58
- private subChildren: NgGridStackWidget[] = [
59
- {x:0, y:0, content: 'regular item'},
60
- {x:1, y:0, w:4, h:4, subGridOpts: {children: this.sub1, class: 'sub1', ...this.subOptions}},
61
- {x:5, y:0, w:3, h:4, subGridOpts: {children: this.sub2, class: 'sub2', ...this.subOptions}},
62
- ]
63
- public nestedGridOptions: NgGridStackOptions = { // main grid options
64
- cellHeight: 50,
65
- margin: 5,
66
- minRow: 2, // don't collapse when empty
67
- acceptWidgets: true,
68
- children: this.subChildren
69
- };
70
- public twoGridOpt1: NgGridStackOptions = {
71
- column: 6,
72
- cellHeight: 50,
73
- margin: 5,
74
- minRow: 1, // don't collapse when empty
75
- removable: '.trash',
76
- acceptWidgets: true,
77
- float: true,
78
- children: [
79
- {x: 0, y: 0, w: 2, h: 2},
80
- {x: 3, y: 1, h: 2},
81
- {x: 4, y: 1},
82
- {x: 2, y: 3, w: 3, maxW: 3, id: 'special', content: 'has maxW=3'},
83
- ]
84
- };
85
- public twoGridOpt2: NgGridStackOptions = { ...this.twoGridOpt1, float: false }
86
- private serializedData?: NgGridStackOptions;
87
-
88
- constructor() {
89
- // give them content and unique id to make sure we track them during changes below...
90
- [...this.items, ...this.subChildren, ...this.sub1, ...this.sub2, ...this.sub0].forEach((w: NgGridStackWidget) => {
91
- if (!w.selector && !w.content && !w.subGridOpts) w.content = `item ${ids}`;
92
- w.id = String(ids++);
93
- });
94
- }
95
-
96
- ngOnInit(): void {
97
- this.onShow(this.show);
98
-
99
- // TEST
100
- // setTimeout(() => {
101
- // if (!this.gridComp) return;
102
- // this.saveGrid();
103
- // // this.clearGrid();
104
- // this.delete();
105
- // this.delete();
106
- // this.loadGrid();
107
- // this.delete();
108
- // this.delete();
109
- // }, 500)
110
- }
111
-
112
- public onShow(val: number) {
113
- this.show = val;
114
-
115
- // set globally our method to create the right widget type
116
- if (val < 3) GridStack.addRemoveCB = undefined;
117
- else GridStack.addRemoveCB = gsCreateNgComponents;
118
-
119
- // let the switch take affect then load the starting values (since we sometimes save())
120
- setTimeout(() => {
121
- let data;
122
- switch(val) {
123
- case 0: data = this.case0Comp?.items; break;
124
- case 1: data = this.case1Comp?.items; break;
125
- case 2: data = this.case2Comp?.items; break;
126
- case 3: data = this.gridComp?.grid?.save(true, true); break;
127
- case 4: data = this.items; break;
128
- case 5: data = this.gridOptionsFull; break;
129
- case 6: data = this.nestedGridOptions; break;
130
- case 7: data = this.twoGridOpt1;
131
- GridStack.setupDragIn('.sidebar .grid-stack-item', { appendTo: 'body', helper: 'clone' });
132
- break;
133
- }
134
- if (this.origTextEl) this.origTextEl.nativeElement.value = JSON.stringify(data, null, ' ');
135
- });
136
- if (this.textEl) this.textEl.nativeElement.value = '';
137
- }
138
-
139
- /** called whenever items change size/position/etc.. */
140
- public onChange(data: nodesCB) {
141
- // TODO: update our TEMPLATE list to match ?
142
- // NOTE: no need for dynamic as we can always use grid.save() to get latest layout, or grid.engine.nodes
143
- console.log('change ', data.nodes.length > 1 ? data.nodes : data.nodes[0]);
144
- }
145
-
146
- public onResizeStop(data: elementCB) {
147
- console.log('resizestop ', data.el.gridstackNode);
148
- }
149
-
150
- /**
151
- * TEST dynamic grid operations - uses grid API directly (since we don't track structure that gets out of sync)
152
- */
153
- public add() {
154
- // TODO: BUG the content doesn't appear until widget is moved around (or another created). Need to force
155
- // angular detection changes...
156
- this.gridComp?.grid?.addWidget({x:3, y:0, w:2, content:`item ${ids}`, id:String(ids++)});
157
- }
158
- public delete() {
159
- let grid = this.gridComp?.grid;
160
- if (!grid) return;
161
- let node = grid.engine.nodes[0];
162
- // delete any children first before subGrid itself...
163
- if (node?.subGrid && node.subGrid.engine.nodes.length) {
164
- grid = node.subGrid;
165
- node = grid.engine.nodes[0];
166
- }
167
- if (node) grid.removeWidget(node.el!);
168
- }
169
- public modify() {
170
- this.gridComp?.grid?.update(this.gridComp?.grid.engine.nodes[0]?.el!, {w:3})
171
- }
172
- public newLayout() {
173
- this.gridComp?.grid?.load([
174
- {x:0, y:1, id:'1', minW:1, w:1}, // new size/constrain
175
- {x:1, y:1, id:'2'},
176
- // {x:2, y:1, id:'3'}, // delete item
177
- {x:3, y:0, w:2, content:'new item'}, // new item
178
- ]);
179
- }
180
-
181
- /**
182
- * ngFor case: TEST TEMPLATE operations - NOT recommended unless you have no GS creating/re-parenting
183
- */
184
- public addNgFor() {
185
- // new array isn't required as Angular detects changes to content with trackBy:identify()
186
- // this.items = [...this.items, { x:3, y:0, w:3, content:`item ${ids}`, id:String(ids++) }];
187
- this.items.push({w:2, content:`item ${ids}`, id:String(ids++)});
188
- }
189
- public deleteNgFor() {
190
- this.items.pop();
191
- }
192
- public modifyNgFor() {
193
- // this will not update the DOM nor trigger gridstackItems.changes for GS to auto-update, so set new option of the gridItem instead
194
- // this.items[0].w = 3;
195
- const gridItem = this.gridComp?.gridstackItems?.get(0);
196
- if (gridItem) gridItem.options = {w:3};
197
- }
198
- public newLayoutNgFor() {
199
- this.items = [
200
- {x:0, y:1, id:'1', minW:1, w:1}, // new size/constrain
201
- {x:1, y:1, id:'2'},
202
- // {x:2, y:1, id:'3'}, // delete item
203
- {x:3, y:0, w:2, content:'new item'}, // new item
204
- ];
205
- }
206
- public clearGrid() {
207
- if (!this.gridComp) return;
208
- this.gridComp.grid?.removeAll();
209
- }
210
- public saveGrid() {
211
- this.serializedData = this.gridComp?.grid?.save(false, true) as GridStackOptions || ''; // no content, full options
212
- if (this.textEl) this.textEl.nativeElement.value = JSON.stringify(this.serializedData, null, ' ');
213
- }
214
- public loadGrid() {
215
- if (!this.gridComp) return;
216
- GridStack.addGrid(this.gridComp.el, this.serializedData);
217
- }
218
-
219
- // ngFor TEMPLATE unique node id to have correct match between our items used and GS
220
- public identify(index: number, w: GridStackWidget) {
221
- return w.id; // or use index if no id is set and you only modify at the end...
222
- }
223
- }
@@ -1,39 +0,0 @@
1
- import { NgModule } from '@angular/core';
2
- import { BrowserModule } from '@angular/platform-browser';
3
-
4
- import { AppComponent } from './app.component';
5
- import { AngularNgForTestComponent } from './ngFor';
6
- import { AngularNgForCmdTestComponent } from './ngFor_cmd';
7
- import { AngularSimpleComponent } from './simple';
8
- import { AComponent, BComponent, CComponent } from './dummy.component';
9
-
10
- // local testing
11
- // import { GridstackModule } from './gridstack.module';
12
- // import { GridstackComponent } from './gridstack.component';
13
- import { GridstackModule, GridstackComponent } from 'gridstack/dist/angular';
14
-
15
- @NgModule({
16
- imports: [
17
- BrowserModule,
18
- GridstackModule,
19
- ],
20
- declarations: [
21
- AngularNgForCmdTestComponent,
22
- AngularNgForTestComponent,
23
- AngularSimpleComponent,
24
- AppComponent,
25
- AComponent,
26
- BComponent,
27
- CComponent,
28
- ],
29
- exports: [
30
- ],
31
- providers: [],
32
- bootstrap: [AppComponent]
33
- })
34
- export class AppModule {
35
- constructor() {
36
- // register all our dynamic components created in the grid
37
- GridstackComponent.addComponentToSelectorType([AComponent, BComponent, CComponent]);
38
- }
39
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * gridstack.component.ts 8.2.1
3
- * Copyright (c) 2022 Alain Dumesny - see GridStack root license
4
- */
5
-
6
- // dummy testing component that will be grid items content
7
-
8
- import { Component, OnDestroy, Input } from '@angular/core';
9
- import { BaseWidget, NgCompInputs } from 'gridstack/dist/angular';
10
-
11
- @Component({
12
- selector: 'app-a',
13
- template: 'Comp A {{text}}',
14
- })
15
- export class AComponent extends BaseWidget implements OnDestroy {
16
- @Input() text: string = 'foo'; // test custom input data
17
- public override serialize(): NgCompInputs | undefined { return this.text ? {text: this.text} : undefined; }
18
- ngOnDestroy() { console.log('Comp A destroyed'); } // test to make sure cleanup happens
19
- }
20
-
21
- @Component({
22
- selector: 'app-b',
23
- template: 'Comp B',
24
- })
25
- export class BComponent extends BaseWidget implements OnDestroy {
26
- ngOnDestroy() { console.log('Comp B destroyed'); }
27
- }
28
-
29
- @Component({
30
- selector: 'app-c',
31
- template: 'Comp C',
32
- })
33
- export class CComponent extends BaseWidget {
34
- }
@@ -1,131 +0,0 @@
1
- /**
2
- * Example using Angular ngFor to loop through items and create DOM items
3
- */
4
-
5
- import { Component, AfterViewInit, Input, ViewChildren, QueryList, ElementRef } from '@angular/core';
6
- import { GridItemHTMLElement, GridStack, GridStackNode, GridStackWidget, Utils } from 'gridstack';
7
-
8
- // unique ids sets for each item for correct ngFor updating
9
- let ids = 1;
10
-
11
- @Component({
12
- selector: "angular-ng-for-test",
13
- template: `
14
- <p><b>ngFor</b>: Example using Angular ngFor to loop through items and create DOM items. This track changes made to the array of items, waits for DOM rendering, then update GS</p>
15
- <button (click)="add()">add item</button>
16
- <button (click)="delete()">remove item</button>
17
- <button (click)="modify()">modify item</button>
18
- <button (click)="newLayout()">new layout</button>
19
- <div class="grid-stack">
20
- <!-- using angular templating to create DOM, otherwise an easier way is to simply call grid.load(items)
21
- NOTE: this example is NOT complete as there are many more properties than listed (minW, maxW, etc....)
22
- -->
23
- <div *ngFor="let n of items; trackBy: identify"
24
- class="grid-stack-item"
25
- [attr.gs-id]="n.id"
26
- [attr.gs-x]="n.x"
27
- [attr.gs-y]="n.y"
28
- [attr.gs-w]="n.w"
29
- [attr.gs-h]="n.h"
30
- #gridStackItem
31
- >
32
- <div class="grid-stack-item-content">item {{ n.id }}</div>
33
- </div>
34
- </div>
35
- `,
36
- // gridstack.min.css and other custom styles should be included in global styles.scss or here
37
- })
38
- export class AngularNgForTestComponent implements AfterViewInit {
39
- /** list of HTML items that we track to know when the DOM has been updated to make/remove GS widgets */
40
- @ViewChildren("gridStackItem") gridstackItems!: QueryList<ElementRef<GridItemHTMLElement>>;
41
-
42
- /** set the items to display. */
43
- @Input() public set items(list: GridStackWidget[]) {
44
- this._items = list || [];
45
- this._items.forEach(w => w.id = w.id || String(ids++)); // make sure a unique id is generated for correct ngFor loop update
46
- }
47
- public get items(): GridStackWidget[] { return this._items}
48
-
49
- private grid!: GridStack;
50
- public _items!: GridStackWidget[];
51
-
52
- constructor() {
53
- this.items = [
54
- {x: 0, y: 0},
55
- {x: 1, y: 1},
56
- {x: 2, y: 2},
57
- ];
58
- }
59
-
60
- // wait until after DOM is ready to init gridstack - can't be ngOnInit() as angular ngFor needs to run first!
61
- public ngAfterViewInit() {
62
- this.grid = GridStack.init({
63
- margin: 5,
64
- float: true,
65
- })
66
- .on('change added', (event: Event, nodes: GridStackNode[]) => this.onChange(nodes));
67
-
68
- // sync initial actual valued rendered (in case init() had to merge conflicts)
69
- this.onChange();
70
-
71
- /**
72
- * this is called when the list of items changes - get a list of nodes and
73
- * update the layout accordingly (which will take care of adding/removing items changed by Angular)
74
- */
75
- this.gridstackItems.changes.subscribe(() => {
76
- const layout: GridStackWidget[] = [];
77
- this.gridstackItems.forEach(ref => {
78
- const n = ref.nativeElement.gridstackNode || this.grid.makeWidget(ref.nativeElement).gridstackNode;
79
- if (n) layout.push(n);
80
- });
81
- this.grid.load(layout); // efficient that does diffs only
82
- })
83
- }
84
-
85
- /** Optional: called when given widgets are changed (moved/resized/added) - update our list to match.
86
- * Note this is not strictly necessary as demo works without this
87
- */
88
- public onChange(list = this.grid.engine.nodes) {
89
- setTimeout(() => // prevent new 'added' items from ExpressionChangedAfterItHasBeenCheckedError. TODO: find cleaner way to sync outside Angular change detection ?
90
- list.forEach(n => {
91
- const item = this._items.find(i => i.id === n.id);
92
- if (item) Utils.copyPos(item, n);
93
- })
94
- , 0);
95
- }
96
-
97
- /**
98
- * CRUD operations
99
- */
100
- public add() {
101
- // new array isn't required as Angular seem to detect changes to content
102
- // this.items = [...this.items, { x:3, y:0, w:3, id:String(ids++) }];
103
- this.items.push({ x:3, y:0, w:3, id:String(ids++) });
104
- }
105
-
106
- public delete() {
107
- this.items.pop();
108
- }
109
-
110
- public modify() {
111
- // this will only update the DOM attr (from the ngFor loop in our template above)
112
- // but not trigger gridstackItems.changes for GS to auto-update, so call GS update() instead
113
- // this.items[0].w = 2;
114
- const n = this.grid.engine.nodes[0];
115
- if (n?.el) this.grid.update(n.el, {w:3});
116
- }
117
-
118
- public newLayout() {
119
- this.items = [ // test updating existing and creating new one
120
- {x:0, y:1, id:'1'},
121
- {x:1, y:1, id:'2'},
122
- // {x:2, y:1, id:3}, // delete item
123
- {x:3, y:0, w:3}, // new item
124
- ];
125
- }
126
-
127
- // ngFor unique node id to have correct match between our items used and GS
128
- identify(index: number, w: GridStackWidget) {
129
- return w.id;
130
- }
131
- }
@@ -1,106 +0,0 @@
1
- /**
2
- * Example using Angular ngFor to loop through items and create DOM items - this uses a custom command.
3
- * NOTE: see the simpler and better (tracks all changes) angular-ng-for-test
4
- */
5
-
6
- import { Component, AfterViewInit, Input, ViewChildren, QueryList, ElementRef } from '@angular/core';
7
- import { Subject, zip } from "rxjs";
8
-
9
- import { GridItemHTMLElement, GridStack, GridStackWidget } from 'gridstack';
10
-
11
- @Component({
12
- selector: "angular-ng-for-cmd-test",
13
- template: `
14
- <p><b>ngFor CMD</b>: Example using Angular ngFor to loop through items, but uses an explicity command to let us update GS (see automatic better way)</p>
15
- <button (click)="add()">add item</button>
16
- <button (click)="delete()">remove item</button>
17
- <button (click)="modify()">modify item</button>
18
- <div class="grid-stack">
19
- <!-- using angular templating to create DOM, otherwise an easier way is to simply call grid.load(items) -->
20
- <div
21
- *ngFor="let n of items; let i = index; trackBy: identify"
22
- [id]="i"
23
- class="grid-stack-item"
24
- [attr.gs-x]="n.x"
25
- [attr.gs-y]="n.y"
26
- [attr.gs-w]="n.w"
27
- [attr.gs-h]="n.h"
28
- #gridStackItem
29
- >
30
- <div class="grid-stack-item-content">item {{ i }}</div>
31
- </div>
32
- </div>
33
- `,
34
- // gridstack.min.css and other custom styles should be included in global styles.scss or here
35
- })
36
- export class AngularNgForCmdTestComponent implements AfterViewInit {
37
- /** list of HTML items that we track to know when the DOM has been updated to make/remove GS widgets */
38
- @ViewChildren("gridStackItem") gridstackItems!: QueryList<ElementRef<GridItemHTMLElement>>;
39
-
40
- /** set the items to display. */
41
- @Input() public items: GridStackWidget[] = [
42
- {x: 0, y: 0},
43
- {x: 1, y: 1},
44
- {x: 2, y: 2},
45
- ];
46
-
47
- private grid!: GridStack;
48
- private widgetToMake: Subject<{
49
- action: "add" | "remove" | "update";
50
- id: number;
51
- }> = new Subject(); // consider to use a state management like ngrx component store to do this
52
-
53
- constructor() {}
54
-
55
- // wait until after DOM is ready to init gridstack - can't be ngOnInit() as angular ngFor needs to run first!
56
- public ngAfterViewInit() {
57
- this.grid = GridStack.init({
58
- margin: 5,
59
- float: true,
60
- });
61
-
62
- // To sync dom manipulation done by Angular and widget manipulation done by gridstack we need to zip the observables
63
- zip(this.gridstackItems.changes, this.widgetToMake).subscribe(
64
- ([changedWidget, widgetToMake]) => {
65
- if (widgetToMake.action === "add") {
66
- this.grid.makeWidget(`#${widgetToMake.id}`);
67
- } else if (widgetToMake.action === "remove") {
68
- const id = String(widgetToMake.id);
69
- // Note: DOM element has been removed by Angular already so look for it through the engine node list
70
- const removeEl = this.grid.engine.nodes.find((n) => n.el?.id === id)?.el;
71
- if (removeEl) this.grid.removeWidget(removeEl);
72
- }
73
- }
74
- );
75
-
76
- // TODO: the problem with this code is that our items list does NOT reflect changes made by GS (user directly changing,
77
- // or conflict during initial layout) and believe the other ngFor example (which does track changes) is also cleaner
78
- // as it doesn't require user creating special action commands nor track 'both' changes using zip().
79
- // TODO: identify() uses index which is not guaranteed to match between invocations (insert/delete in
80
- // middle of list instead of end as demo does)
81
- }
82
-
83
- /**
84
- * CRUD operations
85
- */
86
- public add() {
87
- this.items = [...this.items, { x: 3, y: 0, w: 3 }];
88
- this.widgetToMake.next({ action: "add", id: this.items.length - 1 });
89
- }
90
-
91
- public delete() {
92
- this.items.pop();
93
- this.widgetToMake.next({ action: "remove", id: this.items.length });
94
- }
95
-
96
- // a change of a widget doesn´t change to amount of items in ngFor therefore we don´t need to do it through the zip function above
97
- public modify() {
98
- const updateEl = this.grid.getGridItems().find((el) => el.id === `${0}`);
99
- this.grid.update(updateEl!, { w: 2 });
100
- }
101
-
102
- // ngFor lookup indexing
103
- identify(index: number) {
104
- return index;
105
- }
106
- }