515 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
		
		
			
		
	
	
			515 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| 
								 | 
							
								<html lang="en"><head></head><body><form id="mainForm" method="post" action="http://plnkr.co/edit/?p=preview" target="_self"><input type="hidden" name="files[styles.css]" value="/* Master Styles */
							 | 
						||
| 
								 | 
							
								h1 {
							 | 
						||
| 
								 | 
							
								  color: #369;
							 | 
						||
| 
								 | 
							
								  font-family: Arial, Helvetica, sans-serif;
							 | 
						||
| 
								 | 
							
								  font-size: 250%;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								h2, h3 {
							 | 
						||
| 
								 | 
							
								  color: #444;
							 | 
						||
| 
								 | 
							
								  font-family: Arial, Helvetica, sans-serif;
							 | 
						||
| 
								 | 
							
								  font-weight: lighter;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								body {
							 | 
						||
| 
								 | 
							
								  margin: 2em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								body, input[text], button {
							 | 
						||
| 
								 | 
							
								  color: #888;
							 | 
						||
| 
								 | 
							
								  font-family: Cambria, Georgia;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								a {
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  cursor: hand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button {
							 | 
						||
| 
								 | 
							
								  font-family: Arial;
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  border: none;
							 | 
						||
| 
								 | 
							
								  padding: 5px 10px;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  cursor: hand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #cfd8dc;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								button:disabled {
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  color: #aaa;
							 | 
						||
| 
								 | 
							
								  cursor: auto;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Navigation link styles */
							 | 
						||
| 
								 | 
							
								nav a {
							 | 
						||
| 
								 | 
							
								  padding: 5px 10px;
							 | 
						||
| 
								 | 
							
								  text-decoration: none;
							 | 
						||
| 
								 | 
							
								  margin-right: 10px;
							 | 
						||
| 
								 | 
							
								  margin-top: 10px;
							 | 
						||
| 
								 | 
							
								  display: inline-block;
							 | 
						||
| 
								 | 
							
								  background-color: #eee;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								nav a:visited, a:link {
							 | 
						||
| 
								 | 
							
								  color: #607D8B;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								nav a:hover {
							 | 
						||
| 
								 | 
							
								  color: #039be5;
							 | 
						||
| 
								 | 
							
								  background-color: #CFD8DC;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								nav a.active {
							 | 
						||
| 
								 | 
							
								  color: #039be5;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* items class */
							 | 
						||
| 
								 | 
							
								.items {
							 | 
						||
| 
								 | 
							
								  margin: 0 0 2em 0;
							 | 
						||
| 
								 | 
							
								  list-style-type: none;
							 | 
						||
| 
								 | 
							
								  padding: 0;
							 | 
						||
| 
								 | 
							
								  width: 24em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li {
							 | 
						||
| 
								 | 
							
								  cursor: pointer;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  left: 0;
							 | 
						||
| 
								 | 
							
								  background-color: #EEE;
							 | 
						||
| 
								 | 
							
								  margin: .5em;
							 | 
						||
| 
								 | 
							
								  padding: .3em 0;
							 | 
						||
| 
								 | 
							
								  height: 1.6em;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li:hover {
							 | 
						||
| 
								 | 
							
								  color: #607D8B;
							 | 
						||
| 
								 | 
							
								  background-color: #DDD;
							 | 
						||
| 
								 | 
							
								  left: .1em;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li.selected {
							 | 
						||
| 
								 | 
							
								  background-color: #CFD8DC;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items li.selected:hover {
							 | 
						||
| 
								 | 
							
								  background-color: #BBD8DC;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items .text {
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  top: -3px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								.items .badge {
							 | 
						||
| 
								 | 
							
								  display: inline-block;
							 | 
						||
| 
								 | 
							
								  font-size: small;
							 | 
						||
| 
								 | 
							
								  color: white;
							 | 
						||
| 
								 | 
							
								  padding: 0.8em 0.7em 0 0.7em;
							 | 
						||
| 
								 | 
							
								  background-color: #607D8B;
							 | 
						||
| 
								 | 
							
								  line-height: 1em;
							 | 
						||
| 
								 | 
							
								  position: relative;
							 | 
						||
| 
								 | 
							
								  left: -1px;
							 | 
						||
| 
								 | 
							
								  top: -4px;
							 | 
						||
| 
								 | 
							
								  height: 1.8em;
							 | 
						||
| 
								 | 
							
								  margin-right: .8em;
							 | 
						||
| 
								 | 
							
								  border-radius: 4px 0 0 4px;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/* everywhere else */
							 | 
						||
| 
								 | 
							
								* {
							 | 
						||
| 
								 | 
							
								  font-family: Arial, Helvetica, sans-serif;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.component.ts]" value="import { Component } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'my-app',
							 | 
						||
| 
								 | 
							
								  template: `
							 | 
						||
| 
								 | 
							
								  <div class="container">
							 | 
						||
| 
								 | 
							
								    <h1>Reactive Forms</h1>
							 | 
						||
| 
								 | 
							
								    <hero-list></hero-list>
							 | 
						||
| 
								 | 
							
								  </div>`
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class AppComponent { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/app.module.ts]" value="import { NgModule }            from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { BrowserModule }       from '@angular/platform-browser';
							 | 
						||
| 
								 | 
							
								import { ReactiveFormsModule } from '@angular/forms';  // <-- #1 import module
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { AppComponent }        from './app.component';
							 | 
						||
| 
								 | 
							
								import { HeroDetailComponent } from './hero-detail.component'; // <-- #1 import component
							 | 
						||
| 
								 | 
							
								import { HeroListComponent }   from './hero-list.component';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { HeroService }         from './hero.service'; //  <-- #1 import service
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@NgModule({
							 | 
						||
| 
								 | 
							
								  imports: [
							 | 
						||
| 
								 | 
							
								    BrowserModule,
							 | 
						||
| 
								 | 
							
								    ReactiveFormsModule // <-- #2 add to Angular module imports
							 | 
						||
| 
								 | 
							
								  ],
							 | 
						||
| 
								 | 
							
								  declarations: [
							 | 
						||
| 
								 | 
							
								    AppComponent,
							 | 
						||
| 
								 | 
							
								    HeroDetailComponent, // <-- #3 declare app component
							 | 
						||
| 
								 | 
							
								    HeroListComponent
							 | 
						||
| 
								 | 
							
								  ],
							 | 
						||
| 
								 | 
							
								  exports: [ // export for the DemoModule
							 | 
						||
| 
								 | 
							
								    AppComponent,
							 | 
						||
| 
								 | 
							
								    HeroDetailComponent,
							 | 
						||
| 
								 | 
							
								    HeroListComponent
							 | 
						||
| 
								 | 
							
								  ],
							 | 
						||
| 
								 | 
							
								  providers: [ HeroService ], // <-- #4 provide HeroService
							 | 
						||
| 
								 | 
							
								  bootstrap: [ AppComponent ]
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class AppModule { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/data-model.ts]" value="export class Hero {
							 | 
						||
| 
								 | 
							
								  id = 0;
							 | 
						||
| 
								 | 
							
								  name = '';
							 | 
						||
| 
								 | 
							
								  addresses: Address[];
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export class Address {
							 | 
						||
| 
								 | 
							
								  street = '';
							 | 
						||
| 
								 | 
							
								  city   = '';
							 | 
						||
| 
								 | 
							
								  state  = '';
							 | 
						||
| 
								 | 
							
								  zip    = '';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export const heroes: Hero[] = [
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    id: 1,
							 | 
						||
| 
								 | 
							
								    name: 'Whirlwind',
							 | 
						||
| 
								 | 
							
								    addresses: [
							 | 
						||
| 
								 | 
							
								      {street: '123 Main',  city: 'Anywhere', state: 'CA',  zip: '94801'},
							 | 
						||
| 
								 | 
							
								      {street: '456 Maple', city: 'Somewhere', state: 'VA', zip: '23226'},
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    id: 2,
							 | 
						||
| 
								 | 
							
								    name: 'Bombastic',
							 | 
						||
| 
								 | 
							
								    addresses: [
							 | 
						||
| 
								 | 
							
								      {street: '789 Elm',  city: 'Smallville', state: 'OH',  zip: '04501'},
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    id: 3,
							 | 
						||
| 
								 | 
							
								    name: 'Magneta',
							 | 
						||
| 
								 | 
							
								    addresses: [ ]
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export const states = ['CA', 'MD', 'OH', 'VA'];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero.service.ts]" value="import { Injectable } from '@angular/core';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Observable } from 'rxjs/Observable';
							 | 
						||
| 
								 | 
							
								import { of }         from 'rxjs/observable/of';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/delay';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero, heroes } from './data-model';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Injectable()
							 | 
						||
| 
								 | 
							
								export class HeroService {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  delayMs = 500;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Fake server get; assume nothing can go wrong
							 | 
						||
| 
								 | 
							
								  getHeroes(): Observable<Hero[]> {
							 | 
						||
| 
								 | 
							
								    return of(heroes).delay(this.delayMs); // simulate latency with delay
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Fake server update; assume nothing can go wrong
							 | 
						||
| 
								 | 
							
								  updateHero(hero: Hero): Observable<Hero>  {
							 | 
						||
| 
								 | 
							
								    const oldHero = heroes.find(h => h.id === hero.id);
							 | 
						||
| 
								 | 
							
								    const newHero = Object.assign(oldHero, hero); // Demo: mutate cached hero
							 | 
						||
| 
								 | 
							
								    return of(newHero).delay(this.delayMs); // simulate latency with delay
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero-detail.component.html]" value="<form [formGroup]="heroForm" (ngSubmit)="onSubmit()" novalidate>
							 | 
						||
| 
								 | 
							
								  <div style="margin-bottom: 1em">
							 | 
						||
| 
								 | 
							
								    <button type="submit"
							 | 
						||
| 
								 | 
							
								            [disabled]="heroForm.pristine" class="btn btn-success">Save</button> &nbsp;
							 | 
						||
| 
								 | 
							
								    <button type="reset" (click)="revert()"
							 | 
						||
| 
								 | 
							
								            [disabled]="heroForm.pristine" class="btn btn-danger">Revert</button>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <!-- Hero Detail Controls -->
							 | 
						||
| 
								 | 
							
								  <div class="form-group">
							 | 
						||
| 
								 | 
							
								      <label>Name:
							 | 
						||
| 
								 | 
							
								        <input class="form-control" formControlName="name">
							 | 
						||
| 
								 | 
							
								      </label>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <div formArrayName="secretLairs" class="well well-lg">
							 | 
						||
| 
								 | 
							
								    <div *ngFor="let address of secretLairs.controls; let i=index" [formGroupName]="i" >
							 | 
						||
| 
								 | 
							
								      <!-- The repeated address template -->
							 | 
						||
| 
								 | 
							
								      <h4>Address #{{i + 1}}</h4>
							 | 
						||
| 
								 | 
							
								      <div style="margin-left: 1em;">
							 | 
						||
| 
								 | 
							
								        <div class="form-group">
							 | 
						||
| 
								 | 
							
								          <label>Street:
							 | 
						||
| 
								 | 
							
								            <input class="form-control" formControlName="street">
							 | 
						||
| 
								 | 
							
								          </label>
							 | 
						||
| 
								 | 
							
								        </div>
							 | 
						||
| 
								 | 
							
								        <div class="form-group">
							 | 
						||
| 
								 | 
							
								          <label>City:
							 | 
						||
| 
								 | 
							
								            <input class="form-control" formControlName="city">
							 | 
						||
| 
								 | 
							
								          </label>
							 | 
						||
| 
								 | 
							
								        </div>
							 | 
						||
| 
								 | 
							
								        <div class="form-group">
							 | 
						||
| 
								 | 
							
								          <label>State:
							 | 
						||
| 
								 | 
							
								            <select class="form-control" formControlName="state">
							 | 
						||
| 
								 | 
							
								              <option *ngFor="let state of states" [value]="state">{{state}}</option>
							 | 
						||
| 
								 | 
							
								            </select>
							 | 
						||
| 
								 | 
							
								          </label>
							 | 
						||
| 
								 | 
							
								        </div>
							 | 
						||
| 
								 | 
							
								        <div class="form-group">
							 | 
						||
| 
								 | 
							
								          <label>Zip Code:
							 | 
						||
| 
								 | 
							
								            <input class="form-control" formControlName="zip">
							 | 
						||
| 
								 | 
							
								          </label>
							 | 
						||
| 
								 | 
							
								        </div>
							 | 
						||
| 
								 | 
							
								      </div>
							 | 
						||
| 
								 | 
							
								      <br>
							 | 
						||
| 
								 | 
							
								      <!-- End of the repeated address template -->
							 | 
						||
| 
								 | 
							
								    </div>
							 | 
						||
| 
								 | 
							
								    <button (click)="addLair()" type="button">Add a Secret Lair</button>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								  <div class="form-group">
							 | 
						||
| 
								 | 
							
								    <label>Super power:</label>
							 | 
						||
| 
								 | 
							
								    <label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
							 | 
						||
| 
								 | 
							
								    <label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
							 | 
						||
| 
								 | 
							
								    <label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								  <div class="checkbox">
							 | 
						||
| 
								 | 
							
								    <label class="center-block">
							 | 
						||
| 
								 | 
							
								      <input type="checkbox" formControlName="sidekick">I have a sidekick.
							 | 
						||
| 
								 | 
							
								    </label>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								</form>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>heroForm value: {{ heroForm.value | json}}</p>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<h4>Name change log</h4>
							 | 
						||
| 
								 | 
							
								<div *ngFor="let name of nameChangeLog">{{name}}</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
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/hero-detail.component.ts]" value="import { Component, Input, OnChanges }       from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { FormArray, FormBuilder, FormGroup } from '@angular/forms';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Address, Hero, states } from './data-model';
							 | 
						||
| 
								 | 
							
								import { HeroService }           from './hero.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'hero-detail',
							 | 
						||
| 
								 | 
							
								  templateUrl: './hero-detail.component.html'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class HeroDetailComponent implements OnChanges {
							 | 
						||
| 
								 | 
							
								  @Input() hero: Hero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  heroForm: FormGroup;
							 | 
						||
| 
								 | 
							
								  nameChangeLog: string[] = [];
							 | 
						||
| 
								 | 
							
								  states = states;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(
							 | 
						||
| 
								 | 
							
								    private fb: FormBuilder,
							 | 
						||
| 
								 | 
							
								    private heroService: HeroService) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this.createForm();
							 | 
						||
| 
								 | 
							
								    this.logNameChange();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  createForm() {
							 | 
						||
| 
								 | 
							
								    this.heroForm = this.fb.group({
							 | 
						||
| 
								 | 
							
								      name: '',
							 | 
						||
| 
								 | 
							
								      secretLairs: this.fb.array([]),
							 | 
						||
| 
								 | 
							
								      power: '',
							 | 
						||
| 
								 | 
							
								      sidekick: ''
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnChanges() {
							 | 
						||
| 
								 | 
							
								    this.heroForm.reset({
							 | 
						||
| 
								 | 
							
								      name: this.hero.name
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    this.setAddresses(this.hero.addresses);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get secretLairs(): FormArray {
							 | 
						||
| 
								 | 
							
								    return this.heroForm.get('secretLairs') as FormArray;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  setAddresses(addresses: Address[]) {
							 | 
						||
| 
								 | 
							
								    const addressFGs = addresses.map(address => this.fb.group(address));
							 | 
						||
| 
								 | 
							
								    const addressFormArray = this.fb.array(addressFGs);
							 | 
						||
| 
								 | 
							
								    this.heroForm.setControl('secretLairs', addressFormArray);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  addLair() {
							 | 
						||
| 
								 | 
							
								    this.secretLairs.push(this.fb.group(new Address()));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  onSubmit() {
							 | 
						||
| 
								 | 
							
								    this.hero = this.prepareSaveHero();
							 | 
						||
| 
								 | 
							
								    this.heroService.updateHero(this.hero).subscribe(/* error handling */);
							 | 
						||
| 
								 | 
							
								    this.ngOnChanges();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  prepareSaveHero(): Hero {
							 | 
						||
| 
								 | 
							
								    const formModel = this.heroForm.value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // deep copy of form model lairs
							 | 
						||
| 
								 | 
							
								    const secretLairsDeepCopy: Address[] = formModel.secretLairs.map(
							 | 
						||
| 
								 | 
							
								      (address: Address) => Object.assign({}, address)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // return new `Hero` object containing a combination of original hero value(s)
							 | 
						||
| 
								 | 
							
								    // and deep copies of changed form model values
							 | 
						||
| 
								 | 
							
								    const saveHero: Hero = {
							 | 
						||
| 
								 | 
							
								      id: this.hero.id,
							 | 
						||
| 
								 | 
							
								      name: formModel.name as string,
							 | 
						||
| 
								 | 
							
								      // addresses: formModel.secretLairs // <-- bad!
							 | 
						||
| 
								 | 
							
								      addresses: secretLairsDeepCopy
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    return saveHero;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  revert() { this.ngOnChanges(); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  logNameChange() {
							 | 
						||
| 
								 | 
							
								    const nameControl = this.heroForm.get('name');
							 | 
						||
| 
								 | 
							
								    nameControl.valueChanges.forEach(
							 | 
						||
| 
								 | 
							
								      (value: string) => this.nameChangeLog.push(value)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[app/hero-list.component.html]" value="<h3 *ngIf="isLoading"><i>Loading heroes ... </i></h3>
							 | 
						||
| 
								 | 
							
								<h3 *ngIf="!isLoading">Select a hero:</h3>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<nav>
							 | 
						||
| 
								 | 
							
								  <button (click)="getHeroes()" class="btn btn-primary">Refresh</button>
							 | 
						||
| 
								 | 
							
								  <a *ngFor="let hero of heroes | async" (click)="select(hero)">{{hero.name}}</a>
							 | 
						||
| 
								 | 
							
								</nav>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<div *ngIf="selectedHero">
							 | 
						||
| 
								 | 
							
								  <hr>
							 | 
						||
| 
								 | 
							
								  <h2>Hero Detail</h2>
							 | 
						||
| 
								 | 
							
								  <h3>Editing: {{selectedHero.name}}</h3>
							 | 
						||
| 
								 | 
							
								  <hero-detail [hero]="selectedHero"></hero-detail>
							 | 
						||
| 
								 | 
							
								</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
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="files[app/hero-list.component.ts]" value="import { Component, OnInit } from '@angular/core';
							 | 
						||
| 
								 | 
							
								import { Observable }        from 'rxjs/Observable';
							 | 
						||
| 
								 | 
							
								import 'rxjs/add/operator/finally';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import { Hero }        from './data-model';
							 | 
						||
| 
								 | 
							
								import { HeroService } from './hero.service';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@Component({
							 | 
						||
| 
								 | 
							
								  moduleId: module.id,
							 | 
						||
| 
								 | 
							
								  selector: 'hero-list',
							 | 
						||
| 
								 | 
							
								  templateUrl: 'hero-list.component.html'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								export class HeroListComponent implements OnInit {
							 | 
						||
| 
								 | 
							
								  heroes: Observable<Hero[]>;
							 | 
						||
| 
								 | 
							
								  isLoading = false;
							 | 
						||
| 
								 | 
							
								  selectedHero: Hero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(private heroService: HeroService) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ngOnInit() { this.getHeroes(); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getHeroes() {
							 | 
						||
| 
								 | 
							
								    this.isLoading = true;
							 | 
						||
| 
								 | 
							
								    this.heroes = this.heroService.getHeroes()
							 | 
						||
| 
								 | 
							
								                      // Todo: error handling
							 | 
						||
| 
								 | 
							
								                      .finally(() => this.isLoading = false);
							 | 
						||
| 
								 | 
							
								    this.selectedHero = undefined;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  select(hero: Hero) { this.selectedHero = hero; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[main-final.ts]" value="// tslint:disable:no-unused-variable
							 | 
						||
| 
								 | 
							
								import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
							 | 
						||
| 
								 | 
							
								import { AppModule } from './app/app.module';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								platformBrowserDynamic().bootstrapModule(AppModule);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								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
							 | 
						||
| 
								 | 
							
								*/"><input type="hidden" name="files[index.html]" value="<!DOCTYPE html>
							 | 
						||
| 
								 | 
							
								<html>
							 | 
						||
| 
								 | 
							
								  <head>
							 | 
						||
| 
								 | 
							
								    <title>Hero Form</title>
							 | 
						||
| 
								 | 
							
								    <meta charset="UTF-8">
							 | 
						||
| 
								 | 
							
								    <meta name="viewport" content="width=device-width, initial-scale=1">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    <link rel="stylesheet" href="styles.css">
							 | 
						||
| 
								 | 
							
								    <link rel="stylesheet" href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    <!-- Polyfills for older browsers -->
							 | 
						||
| 
								 | 
							
								    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    <script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
							 | 
						||
| 
								 | 
							
								    <script src="node_modules/reflect-metadata/Reflect.js"></script>
							 | 
						||
| 
								 | 
							
								    <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    <script src="https://cdn.rawgit.com/angular/angular.io/b3c65a9/public/docs/_examples/_boilerplate/systemjs.config.web.js"></script>
							 | 
						||
| 
								 | 
							
								    <script>
							 | 
						||
| 
								 | 
							
								      System.import('main-final.js').catch(function(err){ console.error(err); });
							 | 
						||
| 
								 | 
							
								    </script>
							 | 
						||
| 
								 | 
							
								  </head>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  <body>
							 | 
						||
| 
								 | 
							
								    <my-app>Loading...</my-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
							 | 
						||
| 
								 | 
							
								-->"><input type="hidden" name="tags[0]" value="angular"><input type="hidden" name="tags[1]" value="example"><input type="hidden" name="tags[2]" value="reactive"><input type="hidden" name="tags[3]" value="forms"><input type="hidden" name="private" value="true"><input type="hidden" name="description" value="Angular Example - Angular Reactive Forms (final)"></form><script>document.getElementById("mainForm").submit();</script></body></html>
							 |