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

    <link rel="stylesheet" 
          href="node_modules/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="styles.css">

    <!-- 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.25?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>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').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
-->
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: '<simple-edit-form></simple-edit-form>'
})
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
*/
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';

import { AppComponent }  from './app.component';
import { SimpleEditFormComponent } from './simple-edit-form.component';
import {PhoneNumberPipe } from './PhoneNumber.pipe';

import {ManufacturerService} from './Manufacturer.service';
import {LookupService} from './Lookup.service';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule
  ],
  declarations: [
    AppComponent,
    SimpleEditFormComponent,
    PhoneNumberPipe
  ],
  providers: [ManufacturerService, LookupService],
  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
*/
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

// Compiles the module (asynchronously) with the runtime compiler
// which generates a compiled module factory in memory.
// Then bootstraps with that factory, targeting the browser.
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
*/
/**
 * PLUNKER VERSION
 * (based on systemjs.config.js in angular.io)
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  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',

      // angular bundles
      '@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/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',

      // other libraries
      'rxjs':                      'npm:rxjs',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api',
      'ts':                        'npm:plugin-typescript@4.0.10/lib/plugin.js',
      'typescript':                'npm:typescript@2.0.2/lib/typescript.js',

    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.ts',
        defaultExtension: 'ts'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);


/*
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
*/
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}
import {Component, OnInit } from '@angular/core';

import {Manufacturer} from './manufacturer';

import {LookupService} from './Lookup.service';
import {ManufacturerService} from './Manufacturer.service';

@Component({
  moduleId: module.id,
  selector: 'simple-edit-form',
  templateUrl: 'simple-edit-form.component.html'
})
export class SimpleEditFormComponent implements OnInit{
  
  pageMode : string;
  statesList: string[];
  manufacturer: Manufacturer = new Manufacturer();
  manufacturerPrior: Manufacturer;
  
  constructor(private manufacturerService: ManufacturerService, 
              private lookupService: LookupService){}
  
  ngOnInit() : void {
    this.pageMode = "viewMode";
    this.statesList = this.lookupService.getStates();
    
    //this.manufacturerService.getManufacturerAsync().then(manufacturer =>  this.manufacturer  =manufacturer);
    this.manufacturer = this.manufacturerService.getManufacturer();
    
    this.manufacturerPrior = new Manufacturer();
  
  }
  
  editManufacturer() : void {
    
    //note this is not a replacement for angular.copy().
    //.assign() creates a *shallow* copy, meaning that any properties containing
    //references and not simple types will simply have the reference copied to the new
    //object, instead of copying the values within that reference (i.e. a deep copy)
    //discussion: http://stackoverflow.com/questions/34688517/how-can-i-use-angular-copy-in-angular-2
    //           https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
    Object.assign(this.manufacturerPrior, this.manufacturer);
  
    this.pageMode = "editMode";
  }
  
  newManufacturer() : void {
    
    Object.assign(this.manufacturerPrior, this.manufacturer);
    
    //this works without having assign empty property values
    this.manufacturer = new Manufacturer();
    
    this.pageMode = "editMode";
    
  }
  
  saveManufacturer() : void {
    
    // for some reason, manufacturerForm.valid is not available here
    // It works here: http://plnkr.co/edit/IElMhx2Kcos7VLrI2QfC?p=preview 
    // if we add: import { FORM_DIRECTIVES, ControlGroup, Control, Validators, FormBuilder, Validator, } from '@angular/common';
    // and directives: [FORM_DIRECTIVES]
    // but this doesn't work on the page (maybe need to add to app.module??)
    if (manufacturerForm.checkValidity()) {
      this.manufacturerPrior = new Manufacturer();
      this.pageMode = "viewMode";
    }
  }
  
  cancelEdit() : void {
    Object.assign(this.manufacturer, this.manufacturerPrior);
    this.manufacturerPrior = new Manufacturer();
    this.pageMode = "viewMode";
    
  }
}
<h1>Angular2 Simple Edit Form</h1>

<hr />

<h2>Manufacturer</h2>
<div class="container">
  
    <form id="manufacturerForm" name="manufacturerForm"  method="post" novalidate (ngSubmit)="saveManufacturer()" #manufacturerForm="ngForm">
      <p>
          <label for="nameInput">Name:</label>
          <input type="text" id="nameInput" name="nameInput"  [ngClass]="pageMode" [(ngModel)]="manufacturer.name" required #nameInput="ngModel"/>
          <span class="error"  [hidden]="nameInput.valid || !nameInput.errors.required">Name field is required</span>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.name}}</span>
      </p>
      <p>
          <label for="accountNumberInput">Account #:</label>
          <input type="text" id="accountNumberInput" name="accountNumberInput" #accountNumberInput="ngModel" [ngClass]="pageMode" [(ngModel)]="manufacturer.accountNumber" required minlength="3" [maxlength]="15"/>
          <span class="error"  [hidden]="accountNumberInput.valid || !accountNumberInput.errors.required">Account Number is required</span>
          <span class="error"   [hidden]="accountNumberInput.valid || (!accountNumberInput.errors.minlength && !accountNumberInput.errors.maxlength)">Account Number must be between 3 and 15 chars</span>
          <span class="displayValue"  [ngClass]="pageMode">{{manufacturer.accountNumber}}</span>
      </p>
      <p>
          <label for="credLimitInput">Credit Limit:</label>
          <input type="number" id="creditLimitInput" name="creditLimitInput" [ngClass]="pageMode" [(ngModel)]="manufacturer.creditLimit"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.creditLimit | currency }}</span>
      </p>
      <p>
          <label for="addressLine1Input">Address 1:</label>
          <input type="text" id="addressLine1Input" name="addressLine1Input" [ngClass]="pageMode" [(ngModel)]="manufacturer.addressLine1"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.addressLine1}}</span>
      </p>
      <p>
          <label for="addressLine2Input">Address 2:</label>
          <input type="text" id="addressLine2Input" name="addressLine2Input" [ngClass]="pageMode" [(ngModel)]="manufacturer.addressLine2"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.addressLine2}}</span>
      </p>
      <p>
          <label for="addressCityInput">City:</label>
          <input type="text" id="addressCityInput" name="addressCityInput" [ngClass]="pageMode" [(ngModel)]="manufacturer.addressCity"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.addressCity}}</span>
      </p>
      <p>
          <label for="addressStateSelect">State:</label>
          <select id="addressStateSelect" name="addressStateSelect" [(ngModel)]="manufacturer.addressState" [ngClass]="pageMode">
              <option *ngFor="let state of statesList" [value]="state">{{state}}</option>
          </select>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.addressState}}</span>
      </p>
      <p>
          <label for="addressPostalInput">Postal:</label>
          <input type="text" id="addressPostalInput" name="addressPostalInput" [ngClass]="pageMode" [(ngModel)]="manufacturer.addressPostal"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.addressPostal}}</span>
      </p>
      <p>
          <label for="phoneNumberInput">Phone Number:</label>
          <input type="text" id="phoneNumberInput" name="phoneNumberInput" [ngClass]="pageMode" [(ngModel)]="manufacturer.phoneNumber"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.phoneNumber | phonenumber }}</span>
      </p>
      <p>
          <label for="faxNumberInput">Fax Number:</label>
          <input type="text" id="faxNumberInput" name="faxNumberInput" [ngClass]="pageMode" [(ngModel)]="manufacturer.faxNumber"/>
          <span class="displayValue" [ngClass]="pageMode">{{manufacturer.faxNumber | phonenumber }}</span>
      </p>
      <p>
          <label>Date Modified:</label>
          <span>{{manufacturer.dateModified | date: 'short'}}</span>
      </p>
       <p>
          <label>Date Created:</label>
          <span>{{manufacturer.dateCreated | date: 'short'}}</span>
      </p>
      
        <button type="submit" class="editButton" [ngClass]="pageMode" form="manufacturerForm"  [disabled]="manufacturerForm.invalid">Save</button>
  <button class="editButton" [ngClass]="pageMode" (click)="cancelEdit()">Cancel</button>
     
  </form> 
  
  <button class="viewButton" [ngClass]="pageMode" (click)="editManufacturer()">Edit</button>
  <button class="viewButton" [ngClass]="pageMode" (click)="newManufacturer()">New</button>
  
</div>
export class Manufacturer {
  
  constructor (
    public manufacturerId: number,
    public name: string,
    public accountNumber: string,
    public addressLine1: string,
    public addressLine2: string,
    public addressCity: string,
    public addressPostal: string,
    public addressState: string,
    public phoneNumber: string,
    public faxNumber: string,
    public creditLimit: number,
    public dateModified: Date,
    public dateCreated: Date
    ){}
}
import {Manufacturer} from './manufacturer';
import {MANUFACTURER} from './Manufacturer-mock';
import {Injectable} from '@angular/core';

@Injectable()
export class ManufacturerService {
  getManufacturerAsync(): Promise<Manufacturer> {
    return Promise.resolve(MANUFACTURER);
  }
  
  getManufacturer() : Manufacturer {
    return MANUFACTURER;
    
  }
  
}
import {Manufacturer} from './manufacturer';

export var MANUFACTURER: Manufacturer = 
{
	manufacturerId:10000,
  name:'Giro',
  accountNumber:'4513A56',
  addressLine1:'12326 Parkway Drive',
  addressLine2:'',
  addressCity:'Santa Cruz',
  addressPostal:'84623',
  addressState:'CA',
  phoneNumber:'18004562335',
  faxNumber:'9724513262',
  creditLimit:40000.00,
  dateModified: new Date('6/15/2016 9:03 AM'),
  dateCreated: new Date('3/1/2016 3:00 PM')

};

import {Injectable} from '@angular/core';

@Injectable()
export class LookupService {
  getStates(): string[] {
    return ['IA', 'CA', 'MN','SD','NY','FL', 'AK'];
  }
}
form label {
  width: 150px;
    padding-right: 20px;
    display: inline-block;
    text-align:right;
    font-weight:bold;
}

form input[type=text] {
  width: 250px;
  display: inline-block;
}

form input.viewMode {
  display: none;
}

form input.editMode {
  display:auto;
}

form select.viewMode {
  display:none;
}

form select.editMode {
  display:auto;
}

form .displayValue.viewMode{
  display:auto;
}

form .displayValue.editMode {
  display:none;
}

.error {
  color:red;
}

.viewButton.viewMode {
  display:auto;

}

.viewButton.editMode {
  display:none;

}

.editButton.viewMode {
  display:none;
}

.editButton.editMode {
  display:auto;
}
import {Pipe, PipeTransform} from '@angular/core';

// sample filter via: http://stackoverflow.com/a/12728924/24892

@Pipe({name: 'phonenumber'})
export class PhoneNumberPipe implements PipeTransform {
  transform(telephone: string): string {
    if (!telephone)
        return '';
    var value = telephone.toString().trim().replace(/^\+/, '');

    if (value.match(/[^0-9]/)) {
        return telephone;
    }

    var country, city, number;

    switch (value.length) {
        case 10: // +1PPP####### -> C (PPP) ###-####
            country = 1;
            city = value.slice(0, 3);
            number = value.slice(3);
            break;

        case 11: // +CPPP####### -> CCC (PP) ###-####
            country = value[0];
            city = value.slice(1, 4);
            number = value.slice(4);
            break;

        case 12: // +CCCPP####### -> CCC (PP) ###-####
            country = value.slice(0, 3);
            city = value.slice(3, 5);
            number = value.slice(5);
            break;

        default:
            return telephone;
    }

    if (country == 1) {
        country = "";
    }

    number = number.slice(0, 3) + '-' + number.slice(3);

    return (country + " (" + city + ") " + number).trim();
  }
}