Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ module.exports = function(grunt) {
'dist/es5/gridstack-poly.js': ['src/gridstack-poly.js'],
'dist/src/gridstack.scss': ['src/gridstack.scss'],
'dist/src/gridstack-extra.scss': ['src/gridstack-extra.scss'],
'dist/ng/README.md': ['demo/angular/src/app/README.md'],
// 'dist/ng/gridstack.component.ts': ['demo/angular/src/app/gridstack.component.ts'],
// 'dist/ng/gridstack-item.component.ts': ['demo/angular/src/app/gridstack-item.component.ts'],
'dist/ng/README.md': ['demo/angular/README.md'],
'dist/ng/src/gridstack.component.ts': ['demo/angular/src/gridstack.component.ts'],
'dist/ng/src/gridstack-item.component.ts': ['demo/angular/src/gridstack-item.component.ts'],
'dist/ng/src/gridstack.module.ts': ['demo/angular/src/gridstack.module.ts'],
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ GridStack no longer requires external dependencies as of v1.0.0 (lodash was remo

search for ['gridstack' under NPM](https://www.npmjs.com/search?q=gridstack&ranking=popularity) for latest, more to come...

- **Angular**: we now ship out of the box with Angular wrapper components - see <a href="https://github.com/gridstack/gridstack.js/tree/master/demo/angular/src/app" target="_blank">Angular Demo</a>.
- **Angular**: we now ship out of the box with Angular wrapper components - see <a href="https://github.com/gridstack/gridstack.js/tree/master/demo/angular" target="_blank">Angular Demo</a>.
- **Angular9**: [lb-gridstack](https://github.com/pfms84/lb-gridstack) Note: very old v0.3 gridstack instance so recommend for **concept ONLY if you wish to use directive instead**. teh code has been vented as I use components.
- **AngularJS**: [gridstack-angular](https://github.com/kdietrich/gridstack-angular)
- **Ember**: [ember-gridstack](https://github.com/yahoo/ember-gridstack)
Expand Down
199 changes: 168 additions & 31 deletions demo/angular/README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,168 @@

see [**Angular wrapper doc**](./src/app/README.md) for actual usage. this is generic ng project info...

# Angular

This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.13.

## Development server

Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.

## Code scaffolding

Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.

## Build

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.

## Running unit tests

Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).

## Running end-to-end tests

Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.

## 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.

# Angular wrapper

The Angular [wrapper component](./gridstack.component.ts) <gridstack> is a better way to use Gridstack, but alternative raw [ngFor](./ngFor.ts) or [simple](./simple.ts) demos are also given.

# Dynamic grid items
this is the recommended way if you are going to have multiple grids (alow drag&drop between) or drag from toolbar to create items, or drag to remove items, etc...

I.E. don't use Angular templating to create grid items as that is harder to sync when gridstack will also add/remove items.

HTML
```html
<gridstack [options]="gridOptions">
</gridstack>
```

CSS
```css
@import "gridstack/dist/gridstack.min.css";

.grid-stack {
background: #FAFAD2;
}
.grid-stack-item-content {
text-align: center;
background-color: #18bc9c;
}
```

Code
```ts
import { GridStack, GridStackOptions } from 'gridstack';
import { gsCreateNgComponents } from 'gridstack/dist/ng/gridstack.component';

constructor() {
// use the built in component creation code
GridStack.addRemoveCB = gsCreateNgComponents;
}

// sample grid options and items to load...
public gridOptions: GridStackOptions = {
margin: 5,
float: true,
children: [ // or call load()/addWidget() with same data
{x:0, y:0, minW:2, content:'Item 1'},
{x:1, y:1, content:'Item 2'},
{x:2, y:2, content:'Item 3'},
]
}
```

# More Complete example
In this example will use your actual custom angular components inside each grid item (instead of dummy html content)

HTML
```html
<gridstack [options]="gridOptions" (changeCB)="onChange($event)">
<div empty-content>message when grid is empty</div>
</gridstack>
```

Code
```ts
import { Component } from '@angular/core';
import { GridStack, GridStackOptions } from 'gridstack';
import { GridstackComponent, gsCreateNgComponents, NgGridStackWidget, nodesCB } from 'gridstack/dist/ng/gridstack.component';

// some custom components
@Component({
selector: 'app-a',
template: 'Comp A', // your real ng content goes in each component instead...
})
export class AComponent {
}

@Component({
selector: 'app-b',
template: 'Comp B',
})
export class BComponent {
}

// .... in your module for example
constructor() {
// register all our dynamic components created in the grid
GridstackComponent.addComponentToSelectorType([AComponent, BComponent]);
// set globally our method to create the right widget type
GridStack.addRemoveCB = gsCreateNgComponents;
GridStack.saveCB = gsSaveAdditionalNgInfo;
}

// and now our content will look like instead of dummy html content
public gridOptions: NgGridStackOptions = {
margin: 5,
float: true,
minRow: 1, // make space for empty message
children: [ // or call load()/addWidget() with same data
{x:0, y:0, minW:2, type:'app-a'},
{x:1, y:1, type:'app-b'},
{x:2, y:2, content:'plain html content'},
]
}

// called whenever items change size/position/etc.. see other events
public onChange(data: nodesCB) {
console.log('change ', data.nodes.length > 1 ? data.nodes : data.nodes[0]);
}
```

# ngFor with wrapper
For simple case where you control the children creation (gridstack doesn't do create or re-parenting)

HTML
```html
<gridstack [options]="gridOptions" (changeCB)="onChange($event)">
<gridstack-item *ngFor="let n of items; trackBy: identify" [options]="n">
Item {{n.id}}
</gridstack-item>
</gridstack>
```

Code
```javascript
import { GridStackOptions, GridStackWidget } from 'gridstack';
import { nodesCB } from 'gridstack/dist/ng/gridstack.component';

/** sample grid options and items to load... */
public gridOptions: GridStackOptions = {
margin: 5,
float: true,
}
public items: GridStackWidget[] = [
{x:0, y:0, minW:2, id:'1'}, // must have unique id used for trackBy
{x:1, y:1, id:'2'},
{x:2, y:2, id:'3'},
];

// called whenever items change size/position/etc..
public onChange(data: nodesCB) {
console.log('change ', data.nodes.length > 1 ? data.nodes : data.nodes[0]);
}

// ngFor unique node id to have correct match between our items used and GS
public identify(index: number, w: GridStackWidget) {
return w.id; // or use index if no id is set and you only modify at the end...
}
```

## Demo
You can see a fuller example at [app.component.ts](https://github.com/gridstack/gridstack.js/blob/master/demo/angular/src/app/app.component.ts)

to build the demo, go to demo/angular and run `yarn` + `yarn start` and Navigate to `http://localhost:4200/`

Code now shipped starting with v8.0+ in dist/ng for people to use directly!
## Caveats

- This wrapper needs:
- gridstack v8 to run as it needs the latest changes (use older version that matches GS versions)
- Angular 13+ for dynamic createComponent() API

## *ngFor Caveats
- This wrapper handles well ngFor loops, but if you're using a trackBy function (as I would recommend) and no element id change after an update,
you must manually update the `GridstackItemComponent.option` directly - see [modifyNgFor()](./app.component.ts#L174) example.
- The original client list of items is not updated to match **content** changes made by gridstack (TBD later), but adding new item or removing (as shown in demo) will update those new items. Client could use change/added/removed events to sync that list if they wish to do so.


Would appreciate getting help doing the same for React and Vue (2 other popular frameworks)

-Alain
2 changes: 1 addition & 1 deletion demo/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@angular/platform-browser": "^15.1.1",
"@angular/platform-browser-dynamic": "^15.1.1",
"@angular/router": "^15.1.1",
"gridstack": "^8.1.0",
"gridstack": "^8.1.1",
"rxjs": "~7.8.1",
"tslib": "^2.3.0",
"zone.js": "~0.13.0"
Expand Down
154 changes: 0 additions & 154 deletions demo/angular/src/app/README.md

This file was deleted.

2 changes: 1 addition & 1 deletion demo/angular/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { GridStack, GridStackOptions, GridStackWidget } from 'gridstack';
import { GridstackComponent, NgGridStackOptions, NgGridStackWidget, elementCB, gsCreateNgComponents, nodesCB } from './gridstack.component';
import { GridstackComponent, NgGridStackOptions, NgGridStackWidget, elementCB, gsCreateNgComponents, nodesCB } from '../gridstack.component';
import { AngularSimpleComponent } from './simple';
import { AngularNgForTestComponent } from './ngFor';
import { AngularNgForCmdTestComponent } from './ngFor_cmd';
Expand Down
Loading