<!DOCTYPE html>
<html>
<head>
<base href="." />
<title>angular2 playground</title>
<link data-require="bootstrap-css@*" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
<link data-require="font-awesome@*" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
<link rel="stylesheet" href="style.css" />
<script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
<script src="config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
<html>
/* Styles go here */
pre {
display: block;
padding: 9.5px;
margin: 0 0 10px;
font-size: 13px;
line-height: 1.42857143;
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
### Angular Starter Plunker - Typescript
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': './src',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'rxjs': 'npm:rxjs',
'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';
platformBrowserDynamic().bootstrapModule(AppModule)
//our root app component
import {Component, NgModule, OnInit } from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormGroup, FormArray, FormBuilder, Validators } from '@angular/forms'
@Component({
selector: 'my-app',
templateUrl: './src/app.component.html',
})
export class App implements OnInit {
private _form: FormGroup;
title:string;
constructor(
private _fb: FormBuilder
) {
this.title = 'Deep Nested Fields in Nested Array (Model Driven)! '
}
ngOnInit() {
this._form = this._fb.group({
'teacher': ['', Validators.required],
'schools': this._fb.array([
this._fb.group({
'school_name': ['', Validators.required],
'school_description': [''],
'events': this._fb.array([
this._fb.group({
'event_name': ['']
})
])
})
])
});
}
onSubmit() {
console.log(this._form.value)
}
initSchool() {
return this._fb.group({
'school_name': ['', Validators.required],
'school_description': [''],
'events': this._fb.array([
this._fb.group({
'event_name': ['', Validators.required]
})
])
});
}
addSchool() {
const control = <FormArray>this._form.controls['schools'];
control.push(this.initSchool());
}
removeSchool(i: number) {
const control = <FormArray>this._form.controls['schools'];
control.removeAt(i);
}
initEvents() {
return this._fb.group({
'event_name': ['', Validators.required]
});
}
addEvent(i: number) {
const control = (<FormArray>this._form.controls['schools']).at(i).get('events') as FormArray;
control.push(this.initEvents());
}
removeEvent(i: number) {
const control = (<FormArray>this._form.controls['schools']).at(i).get('events') as FormArray;
control.removeAt(i);
}
}
@NgModule({
imports: [
BrowserModule
FormsModule,
ReactiveFormsModule
],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
<div class="container">
<div class="col-md-8 col-xs-12">
<form [formGroup]="_form" novalidate (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-xs-12">
<div class="card">
<div class="card-header">
<h6>{{title}}</h6>
</div>
<div class="card-block">
<div class="form-group">
<label class="form-control-label">Teacher Name:</label>
<input type="text" class="form-control" placeholder="Teacher" formControlName="teacher" />
<small [hidden]="_form.controls.teacher.valid" class="text-danger">
Teacher Name is required!
</small>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12" formArrayName="schools">
<div *ngFor="let school of _form.controls['schools'].controls; let i=index">
<div class="card">
<div class="card-header text-primary">
<span style="font-weight: 500;">{{i + 1}} -</span>
<span>School Name: {{ _form.value.schools[i].school_name }}</span>
<span class="pull-right" *ngIf="_form.controls['schools'].controls.length > 1" (click)="removeSchool(i)">
<i class="fa fa-remove text-danger"></i>
</span>
</div>
<div class="card-block" formGroupName="{{i}}">
<div class="form-group">
<label class="form-control-label">School Name</label>
<input type="text" class="form-control" placeholder="School Name" formControlName="school_name" />
<small [hidden]="_form.controls.schools.controls[i].controls.school_name.valid" class="text-danger">
School Name is required!
</small>
</div>
<div class="form-group">
<label class="form-control-label">School Description</label>
<textarea rows="3" type="text" class="form-control"
placeholder="Description" formControlName="school_description"></textarea>
</div>
<div class="row" formArrayName="events">
<div *ngFor="let event of school.controls['events'].controls; let idx=index">
<div class="card">
<div class="card-header">
<span style="font-weight: 500;">{{idx + 1}} -</span>
<span>Event Name</span>
<span class="pull-right" *ngIf="school.controls['events'].controls.length > 1" (click)="removeEvent(i)">
<i class="fa fa-remove text-danger"></i>
</span>
</div>
<div formGroupName="{{idx}}">
<div class="card-block">
<div class="form-group col-xs-12">
<label class="form-control-label">Event Name</label>
<input type="text" class="form-control" placeholder="Event Name" formControlName="event_name">
<small [hidden]="school.controls.events.controls[idx].controls.event_name.valid" class="text-danger">
Event Name is required!
</small>
</div>
</div>
</div>
<div class="card-footer">
<a class="btn btn-success btn-minimize pull-right" (click)="addEvent(i)">Add another event +</a>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer text-primary">
<a class="btn" (click)="addSchool()">Add another school +</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-12" style="margin-bottom:10px;">
<button class="btn btn-primary pull-right"
type="submit" [disabled]="!_form.valid">Submit</button>
</div>
</form>
</div>
<div class="col-md-4 col-xs-12">
<div class="card-footer">
<h5>Field Values</h5>
<pre>{{ _form.value | json }}</pre>
</div>
</div>
</div>