<!DOCTYPE html>
<html>
  <head>
    <title>Angular Material Plunker</title>
    
    <!-- Load common libraries -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/typescript/2.1.6/typescript.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.7.2/zone.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.47/system.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/web-animations/2.2.2/web-animations.min.js"></script>


    <!-- Configure SystemJS -->
    <script src="systemjs.config.js"></script>

    <script>
      System
        .import('main.ts')
        .catch(console.error.bind(console));
    </script>
    
    <!-- Load the Angular Material stylesheet -->
    <link href="https://rawgit.com/angular/material2-builds/master/prebuilt-themes/indigo-pink.css" rel="stylesheet">
    <style>body { font-family: Roboto, Arial, sans-serif; margin: 0 }</style>

  </head>

  <body class="mat-app-background">
    <material-app>Loading the Angular Material App...</material-app>
  </body>

</html>

<!--
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
import {Component} from '@angular/core';
import {Http} from '@angular/http'
import {bootstrap} from '@angular/platform-browser-dynamic';
import {MyMaterialComponent} from './material.component';

import 'rxjs/add/operator/map'

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  
  private version: any;
  
  constructor(http: Http) {
    // Display the currently used Material 2 version.
    this.version = http
      .get('https://api.github.com/repos/angular/material2-builds/commits/HEAD')
      .map(res => res.json())
  }
  
}

/*
 Copyright 2016 Google Inc. All Rights Reserved.
 Use of this source code is governed by an MIT-style license that
 can be found in the LICENSE file at http://angular.io/license
 */
<md-toolbar color="primary">
  Angular Material 2 App
</md-toolbar>

<div style="padding: 7px">
  
  <p>
    -----  SOME MATERIAL COMPONENTS  -----<br/>
    <button md-button>Basic Button</button>

    <md-slide-toggle>Slide Toggle</md-slide-toggle>
  </p>
  <br/><br/>
  -----  DYNAMIC FORM EXAMPLE  -----<br/>
  <my-form-material></my-form-material>
</div>



<!--
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
/** Add Transpiler for Typescript */
System.config({
  transpiler: 'typescript',
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  packages: {
    '.': {
      defaultExtension: 'ts'
    },
    'vendor': {
      defaultExtension: 'js'
    }
  }
});

System.config({
  map: {
    'main': 'main.js',
    
    // Angular specific mappings.
    '@angular/core': 'https://unpkg.com/@angular/core/bundles/core.umd.js',
    '@angular/common': 'https://unpkg.com/@angular/common/bundles/common.umd.js',
    '@angular/compiler': 'https://unpkg.com/@angular/compiler/bundles/compiler.umd.js',
    '@angular/animations': "https://unpkg.com/@angular/animations/bundles/animations.umd.js",
    '@angular/animations/browser': 'https://unpkg.com/@angular/animations/bundles/animations-browser.umd.js',
    '@angular/http': 'https://unpkg.com/@angular/http/bundles/http.umd.js',
    '@angular/forms': 'https://unpkg.com/@angular/forms@4.3.1',
    '@angular/router': 'https://unpkg.com/@angular/router/bundles/router.umd.js',
    '@angular/platform-browser': 'https://unpkg.com/@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser/animations': 'https://unpkg.com/@angular/platform-browser/bundles/platform-browser-animations.umd.js',
    '@angular/platform-browser-dynamic': 'https://unpkg.com/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
    '@angular/material': 'https://unpkg.com/@angular/material@2.0.0-beta.8',
    '@angular/cdk': 'https://unpkg.com/@angular/cdk@2.0.0-beta.8',
    "@ng2-dynamic-forms/core": "https://unpkg.com/@ng2-dynamic-forms/core@1.4.20",
    "@ng2-dynamic-forms/ui-material": "https://unpkg.com/@ng2-dynamic-forms/ui-material@1.4.20",

    
    // Third party libraries
    'tslib': 'https://unpkg.com/tslib@1.7.1',
    'rxjs': 'https://unpkg.com/rxjs',
  },
  packages: {
    // Thirdparty barrels.
    'rxjs': { main: 'index' },
  }
});

/*
 Copyright 2016 Google Inc. All Rights Reserved.
 Use of this source code is governed by an MIT-style license that
 can be found in the LICENSE file at http://angular.io/license
 */
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HttpModule} from '@angular/http';
import {AppComponent} from './app.component';
import {MyMaterialComponent} from './material.component';
import {CdkTableModule} from '@angular/cdk'
import {
  MdAutocompleteModule,
  MdButtonModule,
  MdButtonToggleModule,
  MdCardModule,
  MdCheckboxModule,
  MdChipsModule,
  MdCoreModule,
  MdDatepickerModule,
  MdDialogModule,
  MdExpansionModule,
  MdGridListModule,
  MdIconModule,
  MdInputModule,
  MdListModule,
  MdMenuModule,
  MdNativeDateModule,
  MdProgressBarModule,
  MdProgressSpinnerModule,
  MdRadioModule,
  MdRippleModule,
  MdSelectModule,
  MdSidenavModule,
  MdSliderModule,
  MdSlideToggleModule,
  MdSnackBarModule,
  MdTabsModule,
  MdToolbarModule,
  MdTooltipModule,
  OverlayModule 
} from '@angular/material';

import { FormsModule, ReactiveFormsModule, NG_VALIDATORS, NG_ASYNC_VALIDATORS, AbstractControl, ValidationErrors, ValidatorFn, FormGroup } from '@angular/forms';
import { DynamicFormsCoreModule } from "@ng2-dynamic-forms/core";
import { DynamicFormsMaterialUIModule } from "@ng2-dynamic-forms/ui-material";

import { ChangeOptionsService } from "./changeoptions.service";



/**
 * NgModule that includes all Material modules that are required to serve 
 * the Plunker.
 */
@NgModule({
  exports: [
    // CDk
    CdkTableModule,
    
    // Material
    MdAutocompleteModule,
    MdButtonModule,
    MdButtonToggleModule,
    MdCardModule,
    MdCheckboxModule,
    MdChipsModule,
    MdDatepickerModule,
    MdDialogModule,
    MdExpansionModule,
    MdGridListModule,
    MdIconModule,
    MdInputModule,
    MdListModule,
    MdMenuModule,
    MdCoreModule,
    MdProgressBarModule,
    MdProgressSpinnerModule,
    MdRadioModule,
    MdRippleModule,
    MdSelectModule,
    MdSidenavModule,
    MdSlideToggleModule,
    MdSliderModule,
    MdSnackBarModule,
    MdTabsModule,
    MdToolbarModule,
    MdTooltipModule,
    MdNativeDateModule,
    
    // Material (future CDK)
    OverlayModule,
  ]
})
export class PlunkerMaterialModule {}

@NgModule({

  imports: [
    BrowserModule,
    CommonModule,
    HttpModule,
    PlunkerMaterialModule,
    BrowserAnimationsModule,
    FormsModule,
    ReactiveFormsModule,
    DynamicFormsCoreModule.forRoot(), 
    DynamicFormsMaterialUIModule
  ],

  declarations: [AppComponent,MyMaterialComponent],
  bootstrap: [AppComponent],
  providers: [
    ChangeOptionsService,
    {provide: NG_VALIDATORS, useValue: areaValidator, multi: true},
    {provide: NG_ASYNC_VALIDATORS, useValue: areaGroupValidator, multi: true}
    ]
})
export class PlunkerAppModule {}

platformBrowserDynamic().bootstrapModule(PlunkerAppModule);


// Validator for inputModels to chech value if is valid for LandHeight
export function areaValidator(control: AbstractControl): ValidationErrors | null {
    let maxArea:number = 50000
    let hasError = control.value ? !(Number(control.value) >= 0 && Number(control.value) <= maxArea): false;
    return hasError ? {areaValidator: true} : null;
}

// Validator for inputModels to chech value if is valid for LandHeight
  export function areaGroupValidator() {
    return function(formGroup: FormGroup): Promise<ValidationErrors | null> {
      let TotalArea = formGroup.controls.areaInput.value;
      let SubArea = formGroup.controls.subAreaInput.value
      if (SubArea > TotalArea) {
         return new Promise((resolve, reject) => {
            resolve({areaGroupValidator: true});
        }); 
      } else {
        return new Promise((resolve, reject) => {
            resolve(null);
        });
      }
  }
}

/*
 Copyright 2016 Google Inc. All Rights Reserved.
 Use of this source code is governed by an MIT-style license that
 can be found in the LICENSE file at http://angular.io/license
 */
<div class="content-margin" style="width: 50%;">


    <form class="text-center" >

        <dynamic-form-material-control *ngFor="let controlModel of formModel"
                                       [group]="formGroup"
                                       [model]="controlModel"
                                       [hasErrorMessaging]="controlModel.hasErrorMessages"
                                       [showCharacterHint]="controlModel.type === 'INPUT'"
                                       (change)="onChange($event)"></dynamic-form-material-control>

    </form>

    <pre>{{formGroup.value | json}}</pre>

</div>
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
import { FormGroup, FormControl, FormArray } from "@angular/forms";
import {
    DynamicFormService,
    DynamicCheckboxModel,
    DynamicFormControlModel,
    DynamicFormArrayModel
} from "@ng2-dynamic-forms/core";
import { MATERIAL_EXAMPLE_MODEL } from "./material.model";
import { ChangeOptionsService } from "./changeoptions.service";

@Component({

    selector: "my-form-material",
    templateUrl: "./material.component.html",
    encapsulation: ViewEncapsulation.None
})

export class MyMaterialComponent implements OnInit {

    formModel: DynamicFormControlModel[] = MATERIAL_EXAMPLE_MODEL;
    formGroup: FormGroup;

    checkboxControl: FormControl;
    checkboxModel: DynamicCheckboxModel;
    selectControl: DynamicSelectModel;

    arrayControl: FormArray;
    arrayModel: DynamicFormArrayModel;

    constructor(private formService: DynamicFormService, private changeOptionsService: ChangeOptionsService) {
      
    }

    ngOnInit() {

        this.formGroup = this.formService.createFormGroup(this.formModel);

        this.checkboxControl = this.formGroup.controls["exampleCheckbox"] as FormControl;
        this.checkboxModel = this.formService.findById("exampleCheckbox", this.formModel) as DynamicCheckboxModel;

        this.arrayControl = this.formGroup.controls["materialFormArray"] as FormArray;
        this.arrayModel = this.formService.findById("materialFormArray", this.formModel) as DynamicFormArrayModel;
        
        this.selectControl = this.formService.findById("materialSelect", this.formModel) as DynamicSelectModel;
        this.selectControl.options = this.changeOptionsService.newOptions();
    }

    add() {
        this.formService.addFormArrayGroup(this.arrayControl, this.arrayModel);
    }

    remove(index: number) {
        this.formService.removeFormArrayGroup(index, this.arrayControl, this.arrayModel);
    }

    onChange($event) {
        console.log(`CHANGE event on: `, $event);
    }
}
import {
    DynamicCheckboxModel,
    DynamicCheckboxGroupModel,
    DynamicDatePickerModel,
    DynamicInputModel,
    DynamicRadioGroupModel,
    DynamicSelectModel,
    DynamicSliderModel,
    DynamicSwitchModel,
    DynamicTextAreaModel,
    DynamicFormGroupModel
} from "@ng2-dynamic-forms/core";

import { areaValidator, areaGroupValidator } from "./main";


export const MATERIAL_EXAMPLE_MODEL = [
    new DynamicSelectModel<string>(
        {
            id: "materialSelect",
            //label: "Example Select",
            multiple: false,
            options: [
                {
                    label: "Option 1",
                    value: "option-1",
                },
                {
                    label: "Option 2",
                    value: "option-2"
                },
                {
                    label: "Option 3",
                    value: "option-3"
                },
                {
                    label: "Option 4",
                    value: "option-4"
                }
            ],
            placeholder: "Select an option"
        }
    ),

    new DynamicInputModel(
        {
            id: "materialInput",
            list: ["Abies", "Pinus", "Fagus", "Platanus"],
            maxLength: 51,
            placeholder: "Select Plant",
            validators: {
                required: null
            },
            errorMessages: {
                required: "Field is required"
            }
        }
    ),
    new DynamicFormGroupModel(
        {
            id: "areas",
            label: "Forest Area",
            group: [
                    new DynamicInputModel(
                        {
                            id: "areaInput",
                            inputType : "number",
                            min: 0,
                            step: .5,
                            placeholder: "Total Area (Ha)",
                            validators: {
                                required: null,
                                areaValidator: {
                                                  name: areaValidator.name,
                                                  args: null
                                                }
                            },
                            errorMessages: {
                                required: "Field Area is required",
                                areaValidator: "Area [0 - 50.000m]"
                            }
                        }
                    ),
                    new DynamicInputModel(
                        {
                            id: "subAreaInput",
                            inputType : "number",
                            min: 0,
                            step: .5,
                            placeholder: "sub Area input",
                            validators: {
                                required: null,
                                areaValidator: {
                                                  name: areaValidator.name,
                                                  args: null
                                                }
                            },
                            errorMessages: {
                                required: "Field Area is required",
                                areaValidator: "Area [0 - 50.000m]"
                            }
                        }
                    )
                  ],
            asyncValidator : {
              areaGroupValidator:areaGroupValidator
              
            },
            errorMessages: {
                areaGroupValidator: "sub Area > Total Area ERROR !!!"
            }
        }),

    new DynamicDatePickerModel(
        {
            id: "materialDatepicker",
            placeholder: "Material Datepicker",
            value: new Date()
        }
    ),

    new DynamicCheckboxGroupModel(
        {
            id: "materialCheckboxGroup",
            group: [
                new DynamicCheckboxModel(
                    {
                        id: "materialCheckbox1",
                        label: "Checkbox 1"
                    }
                ),
                new DynamicCheckboxModel(
                    {
                        id: "materialCheckbox2",
                        label: "Checkbox 2"
                    }
                )
            ]
        }
    ),

    new DynamicSwitchModel(
        {
            id: "materialSwitch",
            offLabel: "Off",
            onLabel: "On",
            value: false
        }
    ),

    new DynamicRadioGroupModel<string>(
        {
            id: "materialRadioGroup",
            //label: "Example Option",
            options: [
                {
                    label: "Option 1",
                    value: "option-1",
                },
                {
                    disabled: true,
                    label: "Option 2",
                    value: "option-2"
                },
                {
                    label: "Option 3",
                    value: "option-3"
                },
                {
                    label: "Option 4",
                    value: "option-4"
                }
            ],
            relation: [
                {
                    action: "DISABLE",
                    when: [
                        {
                            id: "materialSwitch",
                            value: true
                        }
                    ]
                }
            ],
            value: "option-3"
        }
    ),

    new DynamicSliderModel(
        {
            id: "materialSlider",
            min: 0,
            max: 10,
            step: 1,
            value: 3,
            vertical: false
        }
    ),

    new DynamicTextAreaModel(
        {
            id: "materialTextArea",
            //label: "Example Textarea",
            rows: 1,
            placeholder: "example Textarea",
            validators: {
                required: null
            },
            errorMessages: {
                required: "Field is required"
            }
        }
    ),

    new DynamicCheckboxModel(
        {
            id: "materialCheckbox",
            label: "I do agree"
        }
    )
];
import { Injectable } from '@angular/core';

@Injectable()
export class ChangeOptionsService {
  private N_Categories : Array<any>;
  
  constructor() {
    this.N_Categories = [
                {
                    label: "New Option 1",
                    value: "a-1",
                },
                {
                    label: "New Option 2",
                    value: "a-2"
                },
                {
                    label: "New Option 3",
                    value: "a-3"
                },
                {
                    label: "New Option 4",
                    value: "a-4"
                }
            ]
  }
  
  newOptions() {
    return this.N_Categories;
  }
}