3
3
* Copyright (c) 2022 Alain Dumesny - see GridStack root license
4
4
*/
5
5
6
- import { AfterContentInit , ChangeDetectionStrategy , Component , ContentChildren , ElementRef , EventEmitter , Input ,
7
- NgZone , OnDestroy , OnInit , Output , QueryList , Type , ViewChild , ViewContainerRef , createComponent , EnvironmentInjector } from '@angular/core' ;
6
+ import { AfterContentInit , Component , ContentChildren , ElementRef , EventEmitter , Input ,
7
+ OnDestroy , OnInit , Output , QueryList , Type , ViewChild , ViewContainerRef , reflectComponentType } from '@angular/core' ;
8
8
import { Subject } from 'rxjs' ;
9
9
import { takeUntil } from 'rxjs/operators' ;
10
10
import { GridHTMLElement , GridItemHTMLElement , GridStack , GridStackNode , GridStackOptions , GridStackWidget } from 'gridstack' ;
@@ -17,7 +17,6 @@ export type elementCB = {event: Event, el: GridItemHTMLElement};
17
17
export type nodesCB = { event : Event , nodes : GridStackNode [ ] } ;
18
18
export type droppedCB = { event : Event , previousNode : GridStackNode , newNode : GridStackNode } ;
19
19
20
-
21
20
/** extends to store Ng Component selector, instead/inAddition to content */
22
21
export interface NgGridStackWidget extends GridStackWidget {
23
22
type ?: string ; // component type to create as content
@@ -31,6 +30,7 @@ export interface GridCompHTMLElement extends GridHTMLElement {
31
30
_gridComp ?: GridstackComponent ;
32
31
}
33
32
33
+ /** selector string to runtime Type mapping */
34
34
export type SelectorToType = { [ key : string ] : Type < Object > } ;
35
35
36
36
/**
@@ -49,7 +49,7 @@ export type SelectorToType = {[key: string]: Type<Object>};
49
49
styles : [ `
50
50
:host { display: block; }
51
51
` ] ,
52
- changeDetection : ChangeDetectionStrategy . OnPush ,
52
+ // changeDetection: ChangeDetectionStrategy.OnPush, // IFF you want to optimize and control when ChangeDetection needs to happen...
53
53
} )
54
54
export class GridstackComponent implements OnInit , AfterContentInit , OnDestroy {
55
55
@@ -97,8 +97,14 @@ export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
97
97
* Unfortunately Ng doesn't provide public access to that mapping.
98
98
*/
99
99
public static selectorToType : SelectorToType = { } ;
100
- public static addSelector ( key : string , type : Type < Object > ) {
101
- GridstackComponent . selectorToType [ key ] = type ;
100
+ /** add a list of ng Component to be mapped to selector */
101
+ public static addComponentToSelectorType ( typeList : Array < Type < Object > > ) {
102
+ typeList . forEach ( type => GridstackComponent . selectorToType [ GridstackComponent . getSelector ( type ) ] = type ) ;
103
+ }
104
+ /** return the ng Component selector */
105
+ public static getSelector ( type : Type < Object > ) : string {
106
+ const mirror = reflectComponentType ( type ) ! ;
107
+ return mirror . selector ;
102
108
}
103
109
104
110
private _options ?: GridStackOptions ;
@@ -107,7 +113,8 @@ export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
107
113
private ngUnsubscribe : Subject < void > = new Subject ( ) ;
108
114
109
115
constructor (
110
- private readonly zone : NgZone ,
116
+ // private readonly zone: NgZone,
117
+ // private readonly cd: ChangeDetectorRef,
111
118
private readonly elementRef : ElementRef < GridCompHTMLElement > ,
112
119
) {
113
120
this . el . _gridComp = this ;
@@ -118,19 +125,19 @@ export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
118
125
this . loaded = ! ! this . options ?. children ?. length ;
119
126
this . _grid = GridStack . init ( this . _options , this . el ) ;
120
127
delete this . _options ; // GS has it now
128
+
129
+ this . checkEmpty ( ) ;
121
130
}
122
131
123
132
/** wait until after all DOM is ready to init gridstack children (after angular ngFor and sub-components run first) */
124
133
public ngAfterContentInit ( ) : void {
125
- this . zone . runOutsideAngular ( ( ) => {
126
- // track whenever the children list changes and update the layout...
127
- this . gridstackItems ?. changes
128
- . pipe ( takeUntil ( this . ngUnsubscribe ) )
129
- . subscribe ( ( ) => this . updateAll ( ) ) ;
130
- // ...and do this once at least unless we loaded children already
131
- if ( ! this . loaded ) this . updateAll ( ) ;
132
- this . hookEvents ( this . grid ) ;
133
- } ) ;
134
+ // track whenever the children list changes and update the layout...
135
+ this . gridstackItems ?. changes
136
+ . pipe ( takeUntil ( this . ngUnsubscribe ) )
137
+ . subscribe ( ( ) => this . updateAll ( ) ) ;
138
+ // ...and do this once at least unless we loaded children already
139
+ if ( ! this . loaded ) this . updateAll ( ) ;
140
+ this . hookEvents ( this . grid ) ;
134
141
}
135
142
136
143
public ngOnDestroy ( ) : void {
@@ -158,32 +165,35 @@ export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
158
165
/** check if the grid is empty, if so show alternative content */
159
166
public checkEmpty ( ) {
160
167
if ( ! this . grid ) return ;
161
- this . isEmpty = ! this . grid . engine . nodes . length ;
168
+ const isEmpty = ! this . grid . engine . nodes . length ;
169
+ if ( isEmpty === this . isEmpty ) return ;
170
+ this . isEmpty = isEmpty ;
171
+ // this.cd.detectChanges();
162
172
}
163
173
164
174
/** get all known events as easy to use Outputs for convenience */
165
175
private hookEvents ( grid ?: GridStack ) {
166
176
if ( ! grid ) return ;
167
177
grid
168
- . on ( 'added' , ( event : Event , nodes : GridStackNode [ ] ) => this . zone . run ( ( ) => { this . checkEmpty ( ) ; this . addedCB . emit ( { event, nodes} ) ; } ) )
169
- . on ( 'change' , ( event : Event , nodes : GridStackNode [ ] ) => this . zone . run ( ( ) => this . changeCB . emit ( { event, nodes} ) ) )
170
- . on ( 'disable' , ( event : Event ) => this . zone . run ( ( ) => this . disableCB . emit ( { event} ) ) )
171
- . on ( 'drag' , ( event : Event , el : GridItemHTMLElement ) => this . zone . run ( ( ) => this . dragCB . emit ( { event, el} ) ) )
172
- . on ( 'dragstart' , ( event : Event , el : GridItemHTMLElement ) => this . zone . run ( ( ) => this . dragStartCB . emit ( { event, el} ) ) )
173
- . on ( 'dragstop' , ( event : Event , el : GridItemHTMLElement ) => this . zone . run ( ( ) => this . dragStopCB . emit ( { event, el} ) ) )
174
- . on ( 'dropped' , ( event : Event , previousNode : GridStackNode , newNode : GridStackNode ) => this . zone . run ( ( ) => this . droppedCB . emit ( { event, previousNode, newNode} ) ) )
175
- . on ( 'enable' , ( event : Event ) => this . zone . run ( ( ) => this . enableCB . emit ( { event} ) ) )
176
- . on ( 'removed' , ( event : Event , nodes : GridStackNode [ ] ) => this . zone . run ( ( ) => { this . checkEmpty ( ) ; this . removedCB . emit ( { event, nodes} ) ; } ) )
177
- . on ( 'resize' , ( event : Event , el : GridItemHTMLElement ) => this . zone . run ( ( ) => this . resizeCB . emit ( { event, el} ) ) )
178
- . on ( 'resizestart' , ( event : Event , el : GridItemHTMLElement ) => this . zone . run ( ( ) => this . resizeStartCB . emit ( { event, el} ) ) )
179
- . on ( 'resizestop' , ( event : Event , el : GridItemHTMLElement ) => this . zone . run ( ( ) => this . resizeStopCB . emit ( { event, el} ) ) )
178
+ . on ( 'added' , ( event : Event , nodes : GridStackNode [ ] ) => { this . checkEmpty ( ) ; this . addedCB . emit ( { event, nodes} ) ; } )
179
+ . on ( 'change' , ( event : Event , nodes : GridStackNode [ ] ) => this . changeCB . emit ( { event, nodes} ) )
180
+ . on ( 'disable' , ( event : Event ) => this . disableCB . emit ( { event} ) )
181
+ . on ( 'drag' , ( event : Event , el : GridItemHTMLElement ) => this . dragCB . emit ( { event, el} ) )
182
+ . on ( 'dragstart' , ( event : Event , el : GridItemHTMLElement ) => this . dragStartCB . emit ( { event, el} ) )
183
+ . on ( 'dragstop' , ( event : Event , el : GridItemHTMLElement ) => this . dragStopCB . emit ( { event, el} ) )
184
+ . on ( 'dropped' , ( event : Event , previousNode : GridStackNode , newNode : GridStackNode ) => this . droppedCB . emit ( { event, previousNode, newNode} ) )
185
+ . on ( 'enable' , ( event : Event ) => this . enableCB . emit ( { event} ) )
186
+ . on ( 'removed' , ( event : Event , nodes : GridStackNode [ ] ) => { this . checkEmpty ( ) ; this . removedCB . emit ( { event, nodes} ) ; } )
187
+ . on ( 'resize' , ( event : Event , el : GridItemHTMLElement ) => this . resizeCB . emit ( { event, el} ) )
188
+ . on ( 'resizestart' , ( event : Event , el : GridItemHTMLElement ) => this . resizeStartCB . emit ( { event, el} ) )
189
+ . on ( 'resizestop' , ( event : Event , el : GridItemHTMLElement ) => this . resizeStopCB . emit ( { event, el} ) )
180
190
}
181
191
}
182
192
183
193
/**
184
- * called by GS when a new item needs to be created, which we do as a Angular component, or deleted (skip)
194
+ * can be used when a new item needs to be created, which we do as a Angular component, or deleted (skip)
185
195
**/
186
- function createNgComponents ( host : GridCompHTMLElement | HTMLElement , w : NgGridStackWidget | GridStackOptions , add : boolean , isGrid : boolean ) : HTMLElement | undefined {
196
+ export function gsCreateNgComponents ( host : GridCompHTMLElement | HTMLElement , w : NgGridStackWidget | GridStackOptions , add : boolean , isGrid : boolean ) : HTMLElement | undefined {
187
197
if ( add ) {
188
198
if ( ! host ) return ;
189
199
// create the grid item dynamically - see https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html
@@ -217,14 +227,10 @@ function createNgComponents(host: GridCompHTMLElement | HTMLElement, w: NgGridSt
217
227
}
218
228
219
229
/**
220
- * called when saving the grid - put the extra info of type, otherwise content
230
+ * can be used when saving the grid - make sure we save the content from the field (not HTML as we get ng markups)
231
+ * and can put the extra info of type, otherwise content
221
232
*/
222
- function saveAdditionNgInfo ( n : NgGridStackNode , w : NgGridStackWidget ) {
223
- // NOT needed as we get that by default in this case
224
- // if (n.type) w.type = n.type;
225
- // else if (n.content) w.content = n.content;
233
+ export function gsSaveAdditionNgInfo ( n : NgGridStackNode , w : NgGridStackWidget ) {
234
+ if ( n . type ) w . type = n . type ;
235
+ else if ( n . content ) w . content = n . content ;
226
236
}
227
-
228
- // set globally our method to create the right widget type
229
- GridStack . addRemoveCB = createNgComponents ;
230
- GridStack . saveCB = saveAdditionNgInfo ;
0 commit comments