<!DOCTYPE html>
<html>

<head>
    <title>ag-Grid Using Angular Cell Editor Components </title>

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

    <!-- ag-grid CSS -->
    <link href="https://unpkg.com/ag-grid/dist/styles/ag-grid.css" rel="stylesheet"/>
    <link href="https://unpkg.com/ag-grid/dist/styles/theme-fresh.css" rel="stylesheet"/>


    <!-- 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) {
    System.config({
            transpiler: 'ts',
            typescriptOptions: {
                "target": "es5",
                "module": "commonjs",
                "moduleResolution": "node",
                "sourceMap": true,
                "emitDecoratorMetadata": true,
                "experimentalDecorators": true,
                "removeComments": false,
                "noImplicitAny": true
            },
            meta: {
                'typescript': {
                    "exports": "ts"
                }
            },
            paths: {
                // paths serve as alias
                'npm:': 'https://unpkg.com/'
            },
            map: {
                'app': 'app',
                // angular bundles
                '@angular/core': 'npm:@angular/core@2.4.8/bundles/core.umd.js',
                '@angular/common': 'npm:@angular/common@2.4.8/bundles/common.umd.js',
                '@angular/compiler': 'npm:@angular/compiler@2.4.8/bundles/compiler.umd.js',
                '@angular/platform-browser': 'npm:@angular/platform-browser@2.4.8/bundles/platform-browser.umd.js',
                '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@2.4.8/bundles/platform-browser-dynamic.umd.js',
                '@angular/router': 'npm:@angular/router@2.4.8/bundles/router.umd.js',
                '@angular/forms': 'npm:@angular/forms@2.4.8/bundles/forms.umd.js',
                // other libraries
                'rxjs':                      'npm:rxjs@5.0.0',
                'ts':                        'npm:plugin-typescript@4.0.10/lib/plugin.js',
                'typescript':                'npm:typescript@2.1.1/lib/typescript.js',
                // ag libraries
                'ag-grid-angular': 'npm:ag-grid-angular',
                'ag-grid': 'npm:ag-grid'
            },
            packages: {
                app: {
                    main: './boot.ts',
                    defaultExtension: 'ts'
                },
                'ag-grid': {
                    main: 'main.js'
                }
            }
        }
    );

    if (!global.noBootstrap) {
        bootstrap();
    }

    // Bootstrap the `AppModule`(skip the `app/main.ts` that normally does this)
    function bootstrap() {

        // Stub out `app/main.ts` so System.import('app') doesn't fail if called in the index.html
        System.set(System.normalizeSync('app/boot.ts'), System.newModule({}));

        // bootstrap and launch the app (equivalent to standard main.ts)
        Promise.all([
            System.import('@angular/platform-browser-dynamic'),
            System.import('app/app.module')
        ])
            .then(function (imports) {
                var platform = imports[0];
                var app = imports[1];
                platform.platformBrowserDynamic().bootstrapModule(app.AppModule);
            })
            .catch(function (err) {
                console.error(err);
            });
    }
})(this);
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
import { Component } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'my-app',
    templateUrl: 'app.component.html'
})

export class AppComponent { }
<ag-editor-component></ag-editor-component>
import {NgModule} from "@angular/core";
import {BrowserModule} from "@angular/platform-browser";
import {FormsModule} from "@angular/forms";
// ag-grid
import {AgGridModule} from "ag-grid-angular/main";
// application
import {AppComponent} from "./app.component";
// editor
import {EditorComponent} from "./editor-component-example/editor.component";
import {NumericEditorComponent} from "./editor-component-example/numeric-editor.component";
import {MoodEditorComponent} from "./editor-component-example/mood-editor.component";
import {MoodRendererComponent} from "./editor-component-example/mood-renderer.component";
import {FullRowComponent} from "./editor-component-example/fullrowdetails.component";

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        AgGridModule.withComponents(
            [
                NumericEditorComponent,
                MoodEditorComponent,
                MoodRendererComponent,
                FullRowComponent
            ])
    ],
    declarations: [
        AppComponent,
        EditorComponent,
        NumericEditorComponent,
        MoodEditorComponent,
        MoodRendererComponent,
        FullRowComponent
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}
import {Component} from '@angular/core';

import {ICellRendererAngularComp} from 'ag-grid-angular/main';

@Component({
    selector: 'mood-cell',
    template: `<img width="20px" [src]="imgForMood" />`
})
export class MoodRendererComponent implements ICellRendererAngularComp {
    private params: any;
    private mood: string;
    public imgForMood: string;

    agInit(params: any): void {
        this.params = params;
        this.setMood(params);
    }

    refresh(params: any): void {
        this.params = params;
        this.setMood(params);
    }

    private setMood(params) {
        this.mood = params.value;
        this.imgForMood = this.mood === 'Happy' ? 'https://www.ag-grid.com/images/smiley.png' : 'https://www.ag-grid.com/images/smiley-sad.png';
    };
}

<div style="width: 800px;">
    <h1>Cell Editor Component Example</h1>
    <ag-grid-angular #agGrid style="width: 100%; height: 350px;" class="ag-fresh"
                 [gridOptions]="gridOptions">
    </ag-grid-angular>
</div>
import {Component, ViewContainerRef, ViewChild, AfterViewInit} from '@angular/core';

import {ICellEditorAngularComp} from 'ag-grid-angular/main';

@Component({
    selector: 'numeric-cell',
    template: `<input #input (keydown)="onKeyDown($event)" [(ngModel)]="value">`
})
export class NumericEditorComponent implements ICellEditorAngularComp, AfterViewInit {
    private params: any;
    public value: number;
    private cancelBeforeStart: boolean = false;

    @ViewChild('input', {read: ViewContainerRef}) public input;


    agInit(params: any): void {
        this.params = params;
        this.value = this.params.value;

        // only start edit if key pressed is a number, not a letter
        this.cancelBeforeStart = params.charPress && ('1234567890'.indexOf(params.charPress) < 0);
    }

    getValue(): any {
        return this.value;
    }

    isCancelBeforeStart(): boolean {
        return this.cancelBeforeStart;
    }

    // will reject the number if it greater than 1,000,000
    // not very practical, but demonstrates the method.
    isCancelAfterEnd(): boolean {
        return this.value > 1000000;
    };

    onKeyDown(event): void {
        if (!this.isKeyPressedNumeric(event)) {
            if (event.preventDefault) event.preventDefault();
        }
    }

    // dont use afterGuiAttached for post gui events - hook into ngAfterViewInit instead for this
    ngAfterViewInit() {
        this.input.element.nativeElement.focus();
    }

    private getCharCodeFromEvent(event): any {
        event = event || window.event;
        return (typeof event.which == "undefined") ? event.keyCode : event.which;
    }

    private isCharNumeric(charStr): boolean {
        return !!/\d/.test(charStr);
    }

    private isKeyPressedNumeric(event): boolean {
        var charCode = this.getCharCodeFromEvent(event);
        var charStr = String.fromCharCode(charCode);
        return this.isCharNumeric(charStr);
    }
}
import {Component, ViewContainerRef, ViewChild, AfterViewInit} from '@angular/core';

import {ICellEditorAngularComp} from 'ag-grid-angular/main';

@Component({
    selector: 'editor-cell',
    template: `
        <div #container class="mood" tabindex="0" (keydown)="onKeyDown($event)">
            <img src="https://www.ag-grid.com/images/smiley.png" (click)="onClick(true)" [ngClass]="{'selected' : happy, 'default' : !happy}">
            <img src="https://www.ag-grid.com/images/smiley-sad.png" (click)="onClick(false)" [ngClass]="{'selected' : !happy, 'default' : happy}">
        </div>
    `,
    styles: [`
        .mood {
            border-radius: 15px;
            border: 1px solid grey;
            background: #e6e6e6;
            padding: 15px;
            text-align:center;
            display:inline-block;
            outline:none
        }

        .default {
            padding-left:10px;
            padding-right:10px;
            border: 1px solid transparent;
            padding: 4px;
        }

        .selected {
            padding-left:10px;
            padding-right:10px;
            border: 1px solid lightgreen;
            padding: 4px;
        }
    `]
})
export class MoodEditorComponent implements ICellEditorAngularComp, AfterViewInit {
    private params: any;

    @ViewChild('container', {read: ViewContainerRef}) public container;
    public happy: boolean = false;

    // dont use afterGuiAttached for post gui events - hook into ngAfterViewInit instead for this
    ngAfterViewInit() {
        this.container.element.nativeElement.focus();
    }

    agInit(params: any): void {
        this.params = params;
        this.setHappy(params.value === "Happy");
    }

    getValue(): any {
        return this.happy ? "Happy" : "Sad";
    }

    isPopup(): boolean {
        return true;
    }

    setHappy(happy: boolean): void {
        this.happy = happy;
    }

    toggleMood(): void {
        this.setHappy(!this.happy);
    }

    onClick(happy:boolean) {
        this.setHappy(happy);
        this.params.api.stopEditing();
    }

    onKeyDown(event): void {
        let key = event.which || event.keyCode;
        if (key == 37 ||  // left
            key == 39) {  // right
            this.toggleMood();
            event.stopPropagation();
        }
    }
}
import {Component} from "@angular/core";
import {GridOptions} from "ag-grid/main";
import {NumericEditorComponent} from "./numeric-editor.component";
import {MoodRendererComponent} from "./mood-renderer.component";
import {MoodEditorComponent} from "./mood-editor.component";
import {FullRowComponent} from "./fullrowdetails.component";
@Component({
    moduleId: module.id,
    selector: 'ag-editor-component',
    templateUrl: 'editor.component.html'
})
export class EditorComponent {
    public gridOptions: GridOptions;

    constructor() {
        this.gridOptions = <GridOptions>{};
        this.gridOptions.rowData = this.createRowData();
        this.gridOptions.columnDefs = this.createColumnDefs();
        this.gridOptions.fullWidthCellRendererFramework = FullRowComponent;
     
            
           this.gridOptions.isFullWidthCell = (rowNode: RowNode) => {
            return rowNode.flower

        };

        this.gridOptions.getRowHeight = (params: any) => {
            var rowIsNestedRow = params.node.flower;
            // return 100 when nested row, otherwise return 22
            return rowIsNestedRow ? 100 : 23;
        };
        this.gridOptions.doesDataFlower = (dataItem) => {
            return true;

        };
    }

    private createColumnDefs() {
        return [
                {headerName: "Name", field: "name", width: 300 },

             {headerName: "Name", field: "name", width: 300,cellRenderer: 'group' },
            {
                headerName: "Mood",
                field: "mood",
                cellRendererFramework: MoodRendererComponent,
                cellEditorFramework: MoodEditorComponent,
                editable: true,
                width: 250
            },
            {
                headerName: "Numeric",
                field: "number",
                cellEditorFramework: NumericEditorComponent,
                editable: true,
                width: 250
            },
            {
                headerName: "Numeric",
                field: "number",
                cellEditorFramework: NumericEditorComponent,
                editable: true,
                width: 250
            },
            {
                headerName: "Numeric",
                field: "number",
                cellEditorFramework: NumericEditorComponent,
                editable: true,
                width: 250
            }
        ];
    }

    private createRowData() {
        return [
            {name: "Bob", mood: "Happy", number: 10},
            {name: "Harry", mood: "Sad", number: 3},
            {name: "Sally", mood: "Happy", number: 20},
            {name: "Mary", mood: "Sad", number: 5},
            {name: "John", mood: "Happy", number: 15},
            {name: "Jack", mood: "Happy", number: 25},
            {name: "Sue", mood: "Sad", number: 43},
            {name: "Sean", mood: "Sad", number: 1335},
            {name: "Niall", mood: "Happy", number: 2},
            {name: "Alberto", mood: "Happy", number: 123},
            {name: "Fred", mood: "Sad", number: 532},
            {name: "Jenny", mood: "Happy", number: 34},
            {name: "Larry", mood: "Happy", number: 13},
        ];
    }
}
import { Component, ViewContainerRef, ViewChild, AfterViewInit } from '@angular/core';
import { AgRendererComponent } from 'ag-grid-angular/main';

@Component({
    selector: 'full-width-cell',
    template: `<div class="full-width-panel">
         <div class="full-width-flag">
         Test
          </div>
          <div class="full-width-summary">
           <span class="full-width-title">Test</span><br/>
            <label><b>Population:</b> 1003034039493</label><br/>
            <label><b>Known For:</b> This is a test row</label><br/>
          </div>
          <div class="full-width-center"> latinText
          </div>
        </div>`


    , styles: [`
          .full-width-panel {
        /* undo the white-space setting ag-Fresh puts in */
        white-space: normal;
        height: 100%;
        width: 100%;
        border: 2px solid grey;
        border-style: ridge;
        box-sizing: border-box;
        padding: 5px;
        background-color: darkgray;
    }
    .full-width-flag {
        float: left;
        padding: 6px;
    }
    .full-width-summary {
        float: left;
        /*margin-left: 10px;*/
        margin-right: 10px;
    }
    .full-width-panel label {
        padding-top: 3px;
        display: inline-block;
        font-size: 12px;
    }
    .full-width-center {
        overflow-y: scroll;
        border: 1px solid grey;
        padding: 2px;
        height: 100%;
        box-sizing: border-box;
        font-family: cursive;
        background-color: #fafafa;
    }
    .full-width-center p {
        margin-top: 0px;
    }
    .full-width-title {
        font-size: 20px;
    }

    `]
})


export class FullRowComponent implements AgRendererComponent {
    private params: any;
    public values: string;
    private data: any;
   
    private latinText:string
    @ViewChild('full-width-center', { read: ViewContainerRef }) public messageContainer: any;

    agInit(params: any): void {
        this.params = params;
        this.data = params.node.data;
        this.latinText = '<p>Sample Text in a Paragraph</p><p>Lorem ipsum dolor sit amet, his mazim necessitatibus te, mea volutpat intellegebat at. Ea nec perpetua liberavisse, et modo rebum persius pri. Velit recteque reprimique quo at. Vis ex persius oporteat, esse voluptatum moderatius te vis. Ex agam suscipit aliquando eum. Mediocrem molestiae id pri, ei cibo facilisis mel. Ne sale nonumy sea. Et vel lorem omittam vulputate. Ne prima impedit percipitur vis, erat summo an pro. Id urbanitas deterruisset cum, at legere oportere has.</p>';

    }

}