<!doctype html>
<html>
  <head>
    <base href=".">
    <title>Angular + TypeScript</title>
    <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(console.error.bind(console));
  </script>
  </head>
  <body>
    <app-root>
      Loading...
    </app-root>
  </body>
</html>
* {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  font: 300 15px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
}

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  background: #fff;
  -webkit-font-smoothing: antialiased;
  color: #545e6f;
}

img {
  vertical-align: bottom;
}
img a {
  border: 0;
}
ul,
ol {
  list-style: none;
  margin: 0;
  padding: 0;
}
a {
  color: #9f72e6;
  text-decoration: none;
}
input,
button {
  outline: 0;
}
input[type=text],
input[type=email],
input[type=number],
input[type=password] {
  border: none;
  background: #fff;
  font-size: 13px;
  padding: 6px 30px 6px 10px;
  border-radius: 1px;
  border: 1px solid #ccc;
}
label {
  display: block;
}
a {
  color: #9B5FC6;
}
button:disabled {
  cursor: not-allowed;
  background: #b598e4;
}
p {
  margin: 5px 0;
}

body {
  padding: 10px;
}

h3 {
  font-size: 22px;
  font-weight: 400;
  margin: 0;
}
h4 {
  font-size: 18px;
  font-weight: 300;
  margin: 0;
}
input[type="text"] {
  display: block;
  border: none;
  background: #fff;
  font-size: 15px;
  padding: 6px 30px 6px 10px;
  border-radius: 1px;
  border: 1px solid #ccc;
  margin-top: 10px;
  width: 100%;
}
label {
  margin-bottom: 20px;
}
h3 {
  margin-bottom: 20px;
}
app-root {
  margin: 0 auto;
  display: block;
}
select {
  -webkit-appearance: none;
  text-indent: .01px;
  text-overflow: '';
  overflow: hidden;
  font-family: inherit;
  font-size: 14px;
  padding: 10px 50px 10px 15px;
  border-radius: 0;
  color: rgba(0, 0, 0, 0.7);
  border: 1px solid rgba(0, 0, 0, 0.1);
  outline: none;
  background:
    linear-gradient(45deg, transparent 50%, rgba(0, 0, 0, 0.7) 50%)
    no-repeat calc(100% - 20px) calc(1em + 4px),
    linear-gradient(135deg, rgba(0, 0, 0, 0.7) 50%, transparent 50%)
    no-repeat calc(100% - 15px) calc(1em + 4px);
  background-size: 5px 5px, 5px 5px;
}
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.2.2/lib/typescript.js',
    '@ultimate/ngxerrors': 'npm:@ultimate/ngxerrors/bundle/ultimate.ngxerrors.umd.js'
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'
    },
    rxjs: {
      defaultExtension: 'js'
    }
  }
});
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

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

import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  styles: [`
    .error {
      background: #B52D30;
      color: #fff;
      font-weight: 500;
      font-size: 12px;
      text-transform: uppercase;
      border-radius: 0 0 3px 3px;
      line-height: 1;
      padding: 6px 10px;
      margin-top: -1px;
    }
    .errors {
      border: 1px solid #B52D30;
    }
  `],
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
    
      <h3>ngxErrors</h3>
      <p>Errors shown when "dirty" state is true</p>
      
      <label>
        <input 
          type="text" 
          placeholder="Enter your username"
          formControlName="username"
          [class.errors]="username.hasError('*', ['dirty'])">
          
        <div ngxErrors="username" #username="ngxErrors">
          <div class="error" ngxError="required" [when]="['dirty']">
            Username is required
          </div>
        </div>
        
      </label>
      
      <label>
        <input 
          type="text" 
          placeholder="Enter your password"
          formControlName="password"
          [class.errors]="password.hasError('*', ['dirty'])">
          
        <div ngxErrors="password" #password="ngxErrors">
          <div class="error" ngxError="required" [when]="['dirty']">
            Password is required
          </div>
          <div class="error" [ngxError]="['minlength', 'maxlength']" [when]="['dirty']">
            5 characters minimum, 12 characters maximum
          </div>
        </div>
        
      </label>
      
      <p style="border-top: 1px solid #eee; padding: 20px 0;">
        <a href="https://github.com/UltimateAngular/ngxerrors" target="_blank">
          Go to GitHub repo
        </a>
      </p>
      
    </form>
  `
})
export class AppComponent implements OnInit {
  
  form: FormGroup;
  
  constructor(
    private fb: FormBuilder
  ) {}
  
  ngOnInit() {
    this.form = this.fb.group({
      username: ['', [Validators.required]],
      password: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(12)]]
    });
  }
  
  onSubmit() {}
  
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';

import { NgxErrorsModule } from '@ultimate/ngxerrors';

import { AppComponent } from './app.component.ts';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    NgxErrorsModule
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule {}