<!DOCTYPE html>
<html>
<head>
<title>Demo NGPrime and NGDragula Angular 4</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous" />
<link rel="stylesheet" href="https://unpkg.com/primeng@4.0.0-rc.2/resources/themes/omega/theme.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="https://unpkg.com/primeng@4.0.0-rc.2/resources/primeng.min.css" />
<link rel="stylesheet" href="https://unpkg.com/dragula@3.7.2/dist/dragula.css" crossorigin="anonymous" />
</head>
<body>
<my-app>
Loading...
</my-app>
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.9/Reflect.js"></script>
<script src="https://unpkg.com/zone.js@0.8.5/dist/zone.js"></script>
<script src="https://unpkg.com/systemjs@0.19.41/dist/system.js"></script>
<script src="https://unpkg.com/typescript@2.2.0/lib/typescript.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</body>
</html>
/* Styles go here */
System.config({
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true,
experimentalDecorators: true
},
map: {
app: "./src",
'@angular/core': 'npm:@angular/core@4.0.0/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common@4.0.0/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler@4.0.0/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser@4.0.0/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@4.0.0/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http@4.0.0/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router@4.0.0/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms@4.0.0/bundles/forms.umd.js',
'@angular/animations': 'npm:@angular/animations@4.0.0/bundles/animations.umd.js',
'@angular/core/testing': 'npm:@angular/core@4.0.0/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles@4.0.0/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler@4.0.0/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser@4.0.0/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic@4.0.0/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http@4.0.0/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router@4.0.0/bundles/router-testing.umd.js',
'rxjs': 'npm:rxjs@5.1.0',
'lodash': 'npm:lodash@4.17.4/',
'primeng': 'npm:primeng@4.0.0-rc.2/primeng.js',
'dragula': 'npm:dragula@3.7.2/dist/dragula.js',
'ng2-dragula': 'npm:ng2-dragula@1.3.0/index.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
},
lodash: {
defaultExtension: 'js'
},
primeng: {
defaultExtension: 'js'
}
},
paths: {
'npm:': 'https://unpkg.com/'
}
});
import { NgModule } from '@angular/core';
import {CommonModule} from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import {AppComponent} from './app.component';
import {PrimeDragulaDirective} from './primeDragula';
import {DragulaService} from 'ng2-dragula';
import {
DataTableModule
} from 'primeng';
@NgModule({
imports: [
BrowserModule, CommonModule, FormsModule, DataTableModule
],
declarations: [
AppComponent,
PrimeDragulaDirective
],
providers: [DragulaService]
bootstrap: [ AppComponent ]
})
export class AppModule {}
{
"compilerOptions": {
"baseUrl": "",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"mapRoot": "./",
"module": "es6",
"moduleResolution": "node",
"sourceMap": true,
"target": "es5"
}
}
//our root app component
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {ROUTER_PROVIDERS, ROUTER_DIRECTIVES, RouteParams, RouteConfig, Router, LocationStrategy, HashLocationStrategy} from '@angular2/router';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
import { Component, Input, Output, AfterViewInit, ElementRef, EventEmitter, OnChanges } from '@angular/core';
export class EditableTableColumn {
header: string;
field: string;
type: 'text' | 'checkbox';
required?: boolean;
defaultValue? = '';
}
type RowValue = any;
@Component({
selector: 'my-app',
templateUrl: 'src/app.component.html',
styleUrls: ['src/app.css']
})
export class AppComponent implements OnInit {
@Input() columns: Array<EditableTableColumn> = [];
@Input() rows: RowValue[] = [];
columns = [
{
header: 'Name',
field: 'description',
type: 'text',
required: true,
},
{
header: 'Code',
field: 'code',
type: 'text',
required: true
},
{
header: 'Display',
field: 'display',
type: 'checkbox',
defaultValue: true
}
];
constructor() { }
ngOnInit() {
this.rows = [{description: 'test', code: 'WW', display: true},
{description: 'test1', code:'WW1', display: true},
{description: 'test2', code:'WW2', display: true},
{description: 'test3', code:'WW3', display: true}];
}
}
<div class="header">
<h2>Demo NGPrime and NGDragula Angular 4</h2>
</div>
<div class="container-fluid" style="padding-top:20px;">
<div class="row">
<div class="col-md-12">
<p-dataTable [value]="rows" [tableStyle]="{ 'table-layout': 'auto' }"
[primeDragula]="bag" [dragulaModel]="rows"
[dragulaOptions]="{ childContainerSelector: 'tbody', initAfterView: true }"
#datatable>
<p-column header="Move">
<ng-template pTemplate="body" let-rowData="rowData">
<div class="text-center" *ngIf="rowData !== addedRow"><i class="fa fa-bars"></i></div>
</ng-template>
</p-column>
<p-column *ngFor="let col of columns" [field]="col" [header]="col.header" [style]="{ width: textColumnWidth + '%' }">
<ng-template pTemplate="body" let-col let-rowData="rowData">
<div *ngIf="rowData[editable]" class="editable">
<div *ngIf="col.field.type === 'text'">
<input pInputText class="full-width" type="text" [(ngModel)]="rowData[editData][col.field.field]" />
</div>
<div *ngIf="col.field.type === 'checkbox'" class="text-center">
<input type="checkbox" [(ngModel)]="rowData[editData][col.field.field]" />
</div>
</div>
<div *ngIf="!rowData[editable]">
<div *ngIf="col.field.type === 'text'">
{{ rowData[col.field.field] }}
</div>
<div *ngIf="col.field.type === 'checkbox'" class="text-center">
<i [className]="'fa ' + (rowData[col.field.field] ? 'text-primary fa-check-square-o' : 'text-muted fa-square-o')"></i>
</div>
</div>
</ng-template>
</p-column>
<p-column header="Edit" styleClass="edit">
<ng-template pTemplate="body" let-col let-rowData="rowData">
<div class="text-center">
<span *ngIf="rowData[editable]">
<i *ngIf="rowData !== addedRow" (click)="onRowCancel(rowData)" class="fa fa-times"></i>
<i (click)="onRowSave(rowData)" class="fa fa-save text-primary"></i>
</span>
<i *ngIf="!rowData[editable]" (click)="rowData[editable] = true" class="fa fa-pencil-square-o text-primary"></i>
</div>
</ng-template>
</p-column>
<p-column header="Delete">
<ng-template pTemplate="body" let-rowData="rowData">
<div class="text-center"><i (click)="onRowDelete(rowData)" class="fa fa-trash-o text-danger"></i></div>
</ng-template>
</p-column>
</p-dataTable>
</div>
</div>
</div>
import { Directive, OnChanges, AfterViewInit, OnInit, Input, ElementRef, SimpleChange } from '@angular/core';
import { DragulaService, dragula } from 'ng2-dragula';
@Directive({ selector: '[primeDragula]' })
export class PrimeDragulaDirective implements OnChanges, OnInit, AfterViewInit {
@Input() public primeDragula: string;
@Input() public dragulaModel: any;
@Input() public dragulaOptions: any;
protected container: any;
private drake: any;
private options: any;
private el: ElementRef;
private dragulaService: DragulaService;
public constructor(el: ElementRef, dragulaService: DragulaService) {
this.el = el;
this.dragulaService = dragulaService;
}
ngOnInit(){
this.options = Object.assign({}, this.dragulaOptions);
this.container = this.el.nativeElement;
if(!this.options.initAfterView){
this.initialize();
}
}
ngAfterViewInit() {
if(this.options.initAfterView){
this.initialize();
}
}
//since we dont have access to the ngprime datatable body or table itself we need to bing laters in the angular event cycle
//Once this fires we have a tbody tag to attach to and create the drag drop area from.
//because we need to setup dragula later we needed to create our own version of the directive so we have access to the private property container.
//If ngdragula ever changes that to protected we can just extend that directive outright and override the container.
protected initialize(){
if(this.options.childContainerSelector){
this.container = this.el.nativeElement.querySelector(this.options.childContainerSelector);
this.options.mirrorContainer = this.container;
}
let bag = this.dragulaService.find(this.primeDragula);
let checkModel = () => {
if (this.dragulaModel) {
if (this.drake.models) {
this.drake.models.push(this.dragulaModel);
} else {
this.drake.models = [this.dragulaModel];
}
}
};
if (bag) {
this.drake = bag.drake;
checkModel();
this.drake.containers.push(this.container);
} else {
this.drake = dragula([this.container], this.options);
checkModel();
this.dragulaService.add(this.primeDragula, this.drake);
}
}
public ngOnChanges(changes: { dragulaModel?: SimpleChange }): void {
if (changes && changes.dragulaModel) {
if (this.drake) {
if (this.drake.models) {
let modelIndex = this.drake.models.indexOf(changes.dragulaModel.previousValue);
this.drake.models.splice(modelIndex, 1, changes.dragulaModel.currentValue);
} else {
this.drake.models = [changes.dragulaModel.currentValue];
}
}
}
}
}