import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Validators, FormGroup, FormControl } from '@angular/forms';
import { Product } from './model';

@Component({
    selector: 'kendo-grid-edit-form',
    styles: [`
        .ng-valid   { border-left: 5px solid #42a948; }
        .ng-invalid { border-left: 5px solid #a94442; }
        form.ng-invalid { border-left: 0; }
        .invalid    { color: #a94442; }
    `],
    template: `
        <kendo-dialog *ngIf="active" title="Edit" (close)="onCancel()">
            <form [formGroup]="editForm">
                <div>
                    <label for="ProductName">ProductName</label>
                    <input type="text" formControlName="ProductName" [(ngModel)]="dataItem.ProductName" />
                    <div [hidden]="editForm.controls.ProductName.valid || editForm.controls.ProductName.pristine" class="invalid">
                        ProductName is required
                    </div>
                </div>
                <div>
                    <label for="UnitPrice">UnitPrice</label>
                    <input type="text" formControlName="UnitPrice" [(ngModel)]="dataItem.UnitPrice"/>
                </div>
                <div>
                    <label for="Discontinued">Discontinued</label>
                    <input type="checkbox" formControlName="Discontinued" [(ngModel)]="dataItem.Discontinued"/>
                </div>
                <div>
                    <label for="UnitsInStock">UnitsInStock</label>
                    <input type="text" formControlName="UnitsInStock" [(ngModel)]="dataItem.UnitsInStock"/>
                    <div [hidden]="editForm.controls.UnitsInStock.valid || editForm.controls.UnitsInStock.pristine" class="invalid">
                        UnitsInStock must be between 0 and 99
                    </div>
                </div>
                <div>
                  <label for="gender">Select gender</label>
                    <kendo-combobox
                        formControlName="gender"
                        [data]="genders"
                        [textField]="'text'"
                        [valueField]="'value'"
                        [valuePrimitive]="true"
                    >
                    </kendo-combobox>
                </div>
            </form>

            <kendo-dialog-actions>
                <button class="k-button" (click)="onCancel()">Cancel</button>
                <button class="k-button k-primary" [disabled]="!editForm.valid" (click)="onSave()">Save</button>
            </kendo-dialog-actions>
        </kendo-dialog>
    `
})
export class GridEditFormComponent {
    dataItem;
    editForm;
    @Input() public set model (product: Product) {
        this.dataItem = product;
        product === undefined ? this.active = false: this.active = true;
    }

    @Output() cancel: EventEmitter<any> = new EventEmitter();
    @Output() save: EventEmitter<any> = new EventEmitter();

    constructor() {
        this.editForm = new FormGroup({
            'ProductName': new FormControl("", Validators.required),
            'UnitPrice': new FormControl(),
            'UnitsInStock': new FormControl("", Validators.compose([Validators.required, Validators.pattern('^[0-9]{1,2}')])),
            'Discontinued': new FormControl(false),
            'gender': new FormControl()
        })
    }

    public active: boolean = false;

    public genders: Array<{ text: string, value: number }> = [
        { text: "Male", value: 1 },
        { text: "Female", value: 2 }
    ];
    
    public onSave(): void {
        this.save.emit(this.dataItem);
        this.active = false;
        return false;
    }
    public onCancel(): void {
        this.active = false;
        this.cancel.emit(undefined);
        return false;
    }

    public addProduct() {
        this.model = new Product();
        this.active = true;
    }
}


export class Product {
    constructor(
        public ProductID?: number,
        public ProductName?: string,
        public Discountinued?: boolean,
        public UnitsInStock?: number
    ) { }
}
import { Component, ViewChild } from '@angular/core';
import { Jsonp } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/switchMap';

import { Product } from './model';
import { GridEditFormComponent } from './edit-form.component';

@Component({
  selector: 'my-app',
  template: `
      <kendo-grid [data]="view" [height]="400">
        <kendo-grid-toolbar>
          <button (click)="addProduct()" class="k-button k-button-icontext k-grid-add">Add new</button>
        </kendo-grid-toolbar>

        <kendo-grid-column field="ProductName"></kendo-grid-column>
        <kendo-grid-column field="UnitPrice" title="UnitPrice"></kendo-grid-column>
        <kendo-grid-column field="Discontinued" title="Discontinued"></kendo-grid-column>
        <kendo-grid-column field="UnitsInStock" title="Units In Stock"></kendo-grid-column>
        <kendo-grid-column>
          <template kendoCellTemplate let-dataItem>
            <button (click)="onEdit(dataItem)" class="k-button k-button-icontext k-grid-edit">Edit</button>
            <button (click)="onDelete(dataItem)" class="k-button k-button-icontext k-grid-delete">Delete</button>
          </template>
        </kendo-grid-column>
      </kendo-grid>

      <kendo-grid-edit-form [model]="dataItem" (cancel)="onCancel()" (save)="onSave($event)">
      </kendo-grid-edit-form>
  `
})
export class AppComponent {
    public dataItem: Product;

    @ViewChild(GridEditFormComponent) protected editFormComponent: GridEditFormComponent;

    private view: Array<Product>;

    constructor(private jsonp: Jsonp) {
        this.getProducts()
            .subscribe(data => this.view = data);
    }

    public onEdit(dataItem: any): void {
        this.dataItem = dataItem;
    }

    public onCancel(): void {
        this.dataItem = undefined;
    }

    public addProduct(): void {
        this.editFormComponent.addProduct();
    }

    public onSave(product: Product): void {
        const operation = product.ProductID === undefined ?
            this.createProduct(product) :
            this.saveProducts(product);

        operation.switchMap(x => this.getProducts())
            .subscribe((response: Product[]) => {
                this.view = response;
            });
    }

    public onDelete(e: Product): void {
        this.deleteProduct(e)
            .switchMap(x => this.getProducts())
            .subscribe((response: Product[]) => {
                this.view = response;
            });
    }

    public getProducts(): Observable<Product[]> {
        return this.fetch();
    }

    public saveProducts(data: Product): Observable<Product[]> {
        return this.fetch("update", data);
    }

    public createProduct(data: Product): Observable<Product[]> {
        data.ProductID = null;
        return this.fetch("create", data);
    }

    public deleteProduct(data: Product): Observable<Product[]> {
        return this.fetch("destroy", data);
    }

    private fetch(action: string = "", data?: Product): Observable<Product[]>  {
        return this.jsonp
            .get(`http://demos.telerik.com/kendo-ui/service/Products/${action}?callback=JSONP_CALLBACK${this.serializeModels(data)}`)
            .map(response => response.json());
    }

    private serializeModels(data?: Product): string {
       return data ? `&models=${JSON.stringify([data])}` : '';
    }
}
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule, JsonpModule } from '@angular/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { DialogModule } from '@progress/kendo-angular-dialog';
import { GridModule } from '@progress/kendo-angular-grid';
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';

import { AppComponent }   from './app.component';
import { GridEditFormComponent }   from './edit-form.component';

@NgModule({
  imports: [
    BrowserModule,
    HttpModule,
    JsonpModule,

    FormsModule,
    ReactiveFormsModule,

    GridModule,
    DialogModule,
    DropDownsModule
  ],
  declarations: [
    AppComponent,
    GridEditFormComponent
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }

import { AppModule } from './ng.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2 QuickStart</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="http://www.telerik.com/kendo-angular-ui/npm/node_modules//@telerik/kendo-theme-default/dist/all.css" />
    <!-- 1. Load libraries -->
    <!-- Polyfill(s) for older browsers -->
    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>

    <script src="https://unpkg.com/zone.js@0.6.23?main=browser"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
    <script src="https://unpkg.com/systemjs@0.19.27/dist/system.src.js"></script>

    <!-- 2. Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>

  <!-- 3. Display the application -->
  <body>
    <my-app>Loading...</my-app>
    
  </body>
</html>
(function (global) {
  var angularVersion = '2.0.0';

  System.config({
    // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
    transpiler: 'ts',
    typescriptOptions: {
      tsconfig: true
    },
    meta: {
      'typescript': {
        "exports": "ts"
      }
    },
    paths: {
      // paths serve as alias
      'npm:': 'https://unpkg.com/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: 'app',
      '@progress': 'http://www.telerik.com/kendo-angular-ui/npm/node_modules/@progress',
      '@telerik': 'http://www.telerik.com/kendo-angular-ui/npm/node_modules/@telerik',

      // angular bundles
      '@angular/core': 'npm:@angular/core@' + angularVersion +'/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common@' + angularVersion +'/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler@' + angularVersion +'/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser@' + angularVersion +'/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@' + angularVersion +'/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http@' + angularVersion +'/bundles/http.umd.js',
      '@angular/http/testing': 'npm:@angular/http@' + angularVersion +'/bundles/http-testing.umd.js',
      '@angular/forms': 'npm:@angular/forms@' + angularVersion + '/bundles/forms.umd.js',
      '@angular/router': 'npm:@angular/router@3.0.0-rc.3/bundles/router.umd.js',

      // other libraries
      'rxjs':                       'npm:rxjs',
      'chroma-js':                  'npm:chroma-js@1.2.1',
      'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
      'ts':                         'npm:plugin-typescript@4.0.10/lib/plugin.js',
      'typescript':                 'npm:typescript@1.9.0-dev.20160409/lib/typescript.js'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      "@progress/kendo-angular-grid": {"main":"dist/cdn/js/kendo-angular-grid.js","defaultExtension":"js"},
"@progress/kendo-angular-dialog": {"main":"dist/cdn/js/kendo-angular-dialog.js","defaultExtension":"js"},
"@progress/kendo-angular-dropdowns": {"main":"dist/cdn/js/kendo-angular-dropdowns.js","defaultExtension":"js"},

      app: {
        main: './main.ts',
        defaultExtension: 'ts'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular2-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}