将gridstack.js包装到Angular 2组件中

我有一些Angular 1经验,但我们需要在Angular 2项目中使用gridstack.js 。

我们熟悉gridstack-angular项目,但该项目是在Angular 1中。我认为我遇到的最大问题是Angular 2概念。

任何帮助,将不胜感激。

教程

对于初学者来说, Angular 2 Quickstart是最好的。

然后继续并进入英雄 。 这也是一个很棒的教程。

工具

对于教程,并坦率地建立任何Angular 2应用程序,我强烈建议使用Angular-Cli 。 它使构建Angular 2应用程序变得轻而易举

只需看看Angular-Cli的目录 ,看看它能做些什么


我并网stack.component.html

my-grid-stack.component.ts ( 如何在Angular 2中获取JQuery )

 import { Component, OnInit } from '@angular/core'; declare var $: any; // JQuery @Component({ selector: 'app-my-gridstack', templateUrl: './app/my-grid-stack/my-grid-stack.component.html', styleUrls: ['./app/my-grid-stack/my-grid-stack.component.css'] }) export class MyGridStackComponent implements OnInit { constructor() { } ngOnInit() { var options = { cell_height: 80, vertical_margin: 10 }; $('.grid-stack').gridstack(options); } } 

然后我将gridstack.js文件放在src/assets/libs/gridstack文件夹中。

然后不要忘记在index.html导入

  

我们最终创建了两个指令:GridStackDirective和GridStackItemDirective –

grid-stack-directive.ts:

 import { Directive, OnInit, Input, ElementRef, Renderer } from '@angular/core'; declare var $: any; // JQuery @Directive({ selector: '[gridStack]' }) export class GridStackDirective implements OnInit { @Input() w: number; @Input() animate: boolean; constructor( private el: ElementRef, private renderer: Renderer ) { renderer.setElementAttribute(el.nativeElement, "class", "grid-stack"); } ngOnInit() { let renderer = this.renderer; let nativeElement = this.el.nativeElement; let animate: string = this.animate ? "yes" : "no"; renderer.setElementAttribute(nativeElement, "data-gs-width", String(this.w)); if(animate == "yes") { renderer.setElementAttribute(nativeElement, "data-gs-animate", animate); } let options = { cellHeight: 80, verticalMargin: 10 }; // TODO: listen to an event here instead of just waiting for the time to expire setTimeout(function () { $('.grid-stack').gridstack(options); }, 300); } } 

grid-stack-item-directive.ts:

 import { Directive, ElementRef, Input, Renderer, OnInit } from '@angular/core'; @Directive({ selector: '[gridStackItem]' }) export class GridStackItemDirective { @Input() x: number; @Input() y: number; @Input() w: number; @Input() h: number; @Input() minWidth: number; @Input() canResize: boolean; constructor( private el: ElementRef, private renderer: Renderer ) { renderer.setElementAttribute(el.nativeElement, "class", "grid-stack-item"); } ngOnInit(): void { let renderer = this.renderer; let nativeElement = this.el.nativeElement; let cannotResize: string = this.canResize ? "yes" : "no"; let elementText: string = '
' + nativeElement.innerHTML + '
'; // TODO: Find the Angular(tm) way to do this ... nativeElement.innerHTML = elementText; renderer.setElementAttribute(nativeElement, "data-gs-x", String(this.x)); renderer.setElementAttribute(nativeElement, "data-gs-y", String(this.y)); renderer.setElementAttribute(nativeElement, "data-gs-width", String(this.w)); renderer.setElementAttribute(nativeElement, "data-gs-height", String(this.h)); if(this.minWidth) { renderer.setElementAttribute(nativeElement, "data-gs-min-width", String(this.minWidth)); } if(cannotResize == "yes") { renderer.setElementAttribute(nativeElement, "data-gs-no-resize", cannotResize); } } }

app.component.html:

 

My First Grid Stack Angular 2 App

Demo


1
2
Drag me!
4
5
6
7
8
9
10
11

index.html:

   Angular QuickStart                                     Loading...   

我们尝试在gridstack.js网页上复制演示网格。 如果你要运行它并且希望它看起来像他们的那样,你需要从他们的站点获取一些.css文件,.js文件等。

基于用户@Etchelon和@ user3758236的答案

我创建了这个gridstack angular 4库模块,方便使用

它有一个简单的用法,我在那里添加了一个动态生成小部件的例子

       

干杯:)

基于@ user3758236的答案,我开发了几个组件,而不是只有指令:

interfaces.ts:

 export interface IGridConfiguration { width: number; height: number; x: number; y: number; } 

网格stack.component.ts:

 import { Component, HostBinding, OnInit, Input, OnChanges, AfterViewInit, AfterContentInit, ElementRef, Renderer, QueryList, ContentChildren } from '@angular/core'; import { GridStackItemComponent } from "./grid-stack-item.component"; import { IGridConfiguration } from "./interfaces"; declare var jQuery: any; // JQuery declare var _: any; @Component({ moduleId: module.id, selector: 'grid-stack', template: ``, styles: [":host { display: block; }"] }) export class GridStackComponent implements OnInit, OnChanges, AfterContentInit { @HostBinding("class") cssClass = "grid-stack"; @Input() width: number; @Input() animate: boolean; @Input() float: boolean; @ContentChildren(GridStackItemComponent) items: QueryList; constructor( private _el: ElementRef, private _renderer: Renderer ) { } private _jGrid: any = null; private _grid: any = null; ngOnInit() { let nativeElement = this._el.nativeElement; this._renderer.setElementAttribute(nativeElement, "data-gs-width", String(this.width)); let options = { cellHeight: 100, verticalMargin: 10, animate: this.animate, auto: false, float: this.float }; _.delay(() => { const jGrid = jQuery(nativeElement).gridstack(options); jGrid.on("change", (e: any, items: any) => { console.log("GridStack change event! event: ", e, "items: ", items); _.each(items, (item: any) => this.widgetChanged(item)); }); this._jGrid = jGrid; this._grid = this._jGrid.data("gridstack"); }, 50); } ngOnChanges(): void { } ngAfterContentInit(): void { const makeWidget = (item: GridStackItemComponent) => { const widget = this._grid.makeWidget(item.nativeElement); item.jGridRef = this._grid; item.jWidgetRef = widget; }; // Initialize widgets this.items.forEach(item => makeWidget(item)); // Also when they are rebound this.items .changes .subscribe((items: QueryList) => { if (!this._grid) { _.delay(() => this.items.notifyOnChanges(), 50); return; } items.forEach(item => makeWidget(item)); }); } private widgetChanged(change: IWidgetDragStoppedEvent): void { var jWidget = change.el; var gridStackItem = this.items.find(item => item.jWidgetRef !== null ? item.jWidgetRef[0] === jWidget[0] : false); if (!gridStackItem) return; gridStackItem.update(change.x, change.y, change.width, change.height); } } interface IWidgetDragStoppedEvent extends IGridConfiguration { el: any[]; } 

网格堆叠item.component.ts

 import { Component, ComponentRef, ElementRef, Input, Output, HostBinding, Renderer } from "@angular/core"; import { EventEmitter, OnInit, OnChanges, OnDestroy, AfterViewInit, ViewChild, ViewContainerRef } from "@angular/core"; import { IGridConfiguration } from "./interfaces"; import { DynamicComponentService } from "./dynamic-component.service"; @Component({ moduleId: module.id, selector: "grid-stack-item", template: ` 
`, styleUrls: ["./grid-stack-item.component.css"] }) export class GridStackItemComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { @HostBinding("class") cssClass = "grid-stack-item"; @ViewChild("contentPlaceholder", { read: ViewContainerRef }) contentPlaceholder: ViewContainerRef; @Input() initialX: number; @Input() initialY: number; @Input() initialWidth: number; @Input() initialHeight: number; @Input() minWidth: number; @Input() canResize: boolean; @Input() contentTemplate: string; contentComponentRef: ComponentRef = null; @Output() onGridConfigurationChanged = new EventEmitter(); private _currentX: number; private _currentY: number; private _currentWidth: number; private _currentHeight: number; jGridRef: any = null; private _jWidgetRef: any = null; get jWidgetRef(): any { return this._jWidgetRef; } set jWidgetRef(val: any) { if (!!this._jWidgetRef) this._jWidgetRef.off("change"); this._jWidgetRef = val; this._jWidgetRef.on("change", function () { console.log("Change!!", arguments); }); } update(x: number, y: number, width: number, height: number): void { if (x === this._currentX && y === this._currentY && width === this._currentWidth && height === this._currentHeight) return; this._currentX = x; this._currentY = y; this._currentWidth = width; this._currentHeight = height; this.onGridConfigurationChanged.emit({ x: x, y: y, width: width, height: height }); } get nativeElement(): HTMLElement { return this.el.nativeElement; } constructor( private el: ElementRef, private renderer: Renderer, private componentService: DynamicComponentService ) { } ngOnInit(): void { let renderer = this.renderer; let nativeElement = this.nativeElement; let cannotResize: string = this.canResize ? "yes" : "no"; renderer.setElementAttribute(nativeElement, "data-gs-x", String(this.initialX)); renderer.setElementAttribute(nativeElement, "data-gs-y", String(this.initialY)); renderer.setElementAttribute(nativeElement, "data-gs-width", String(this.initialWidth)); renderer.setElementAttribute(nativeElement, "data-gs-height", String(this.initialHeight)); if (this.minWidth) { renderer.setElementAttribute(nativeElement, "data-gs-min-width", String(this.minWidth)); } if (cannotResize == "yes") { renderer.setElementAttribute(nativeElement, "data-gs-no-resize", cannotResize); } } ngOnChanges(): void { // TODO: check that these properties are in the SimpleChanges this._currentX = this.initialX; this._currentY = this.initialY; this._currentWidth = this.initialWidth; this._currentHeight = this.initialHeight; } ngAfterViewInit(): void { if (!!this.contentTemplate) { this.componentService.getDynamicComponentFactory({ selector: `grid-stack-item-${Date.now()}`, template: this.contentTemplate }) .then(factory => { this.contentComponentRef = this.contentPlaceholder.createComponent(factory); }) } } ngOnDestroy(): void { if (this.contentComponentRef !== null) this.contentComponentRef.destroy(); } }

后一个组件使用一个服务来创建动态组件,你可以在stackoverflow上的其他地方找到它。

用法如下: