import { Component, OnInit } from '@angular/core';
import { User } from './user.interface';
import { EqualValidator } from './equal-validator.directive';
@Component({
moduleId: module.id,
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
directives: [EqualValidator]
})
export class AppComponent implements OnInit {
public user: User;
private hasEmail: boolean;
public bffEmail: string = ''; //BFF Emulation
ngOnInit() {
this.user = {
bestEmail: this.bffEmail,
email: '',
confirmEmail: '',
password: '',
confirmPassword: '',
conditions: false
}
this.noEmail = (this.bffEmail != '' ? true : false);
}
save(model: User, isValid: boolean) {
// call API to save customer
console.log(model, isValid);
}
}
import { bootstrap } from '@angular/platform-browser-dynamic';
import { disableDeprecatedForms, provideForms } from '@angular/forms';
import 'rxjs/Rx';
import { AppComponent } from './app.component';
bootstrap(AppComponent, [
disableDeprecatedForms(),
provideForms(),
]);
<!DOCTYPE html>
<html>
<head>
<title>Confirm Password Custom Validator Directive</title>
<!--optional bootstrap for faster styling-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Polyfill(s) for older browsers -->
<script src="https://npmcdn.com/core-js/client/shim.min.js"></script>
<script src="https://npmcdn.com/zone.js@0.6.12?main=browser"></script>
<script src="https://npmcdn.com/reflect-metadata@0.1.3"></script>
<script src="https://npmcdn.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>
<app-root>my-app loading ...</app-root>
</body>
</html>
/**
* PLUNKER VERSION (based on systemjs.config.js in angular.io)
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function(global) {
var ngVer = '@2.0.0-rc.4'; // lock in the angular package version; do not let it float to current!
var routerVer = '@3.0.0-beta.2'; // lock router version
var formsVer = '@0.2.0'; // lock forms version
//map tells the System loader where to look for things
var map = {
'app': 'app',
'@angular': 'https://npmcdn.com/@angular', // sufficient if we didn't pin the version
'@angular/router': 'https://npmcdn.com/@angular/router' + routerVer,
'@angular/forms': 'https://npmcdn.com/@angular/forms' + formsVer,
'angular2-in-memory-web-api': 'https://npmcdn.com/angular2-in-memory-web-api', // get latest
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6',
'ts': 'https://npmcdn.com/plugin-typescript@4.0.10/lib/plugin.js',
'typescript': 'https://npmcdn.com/typescript@1.9.0-dev.20160409/lib/typescript.js',
};
//packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'http',
'platform-browser',
'platform-browser-dynamic',
'router-deprecated',
'upgrade',
];
// Add map entries for each angular package
// only because we're pinning the version with `ngVer`.
ngPackageNames.forEach(function(pkgName) {
map['@angular/'+pkgName] = 'https://npmcdn.com/@angular/' + pkgName + ngVer;
});
// Add package entries for angular packages
ngPackageNames.forEach(function(pkgName) {
// Bundled (~40 requests):
packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
// Individual files (~300 requests):
//packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
// No umd for router yet
packages['@angular/router'] = { main: 'index.js', defaultExtension: 'js' };
// Forms not on rc yet
packages['@angular/forms'] = { main: 'index.js', defaultExtension: 'js' };
var config = {
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
typescriptOptions: {
tsconfig: true
},
meta: {
'typescript': {
"exports": "ts"
}
},
map: map,
packages: packages
};
System.config(config);
})(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
}
}
<div class="container">
<h1>Add user</h1>
<form #f="ngForm" novalidate (ngSubmit)="save(f.value, f.valid)">
<div class="form-group" [hidden]="!noEmail">
<label for="">Best Email</label>
<input type="email" class="form-control" name="bestEmail" [ngModel]="user.bestEmail"
required #bestEmail="ngModel" [disabled]="true">
<br>
<button type="button" class="btn btn-default" (click)="noEmail = !noEmail">Edit</button>
</div>
<div class="form-group" [hidden]="noEmail">
<label for="">Email</label>
<input autofocus type="text" class="form-control" name="email" [ngModel]="user.email"
required validateEqual="confirmEmail" reverse="true" #email="ngModel"
pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$" placeHolder="Type Email"
[ngClass]="{'error-border': !(email.valid || (email.pristine && !f.submitted))}">
<small [hidden]="email.valid || (email.pristine && !f.submitted)" class="text-danger">
Wrong format
</small>
<!--<pre *ngIf="email.errors" class="margin-20">{{ email.errors | json }}</pre>-->
<br>
<label for="">Email Confirm</label>
<input type="text" class="form-control" name="confirmEmail" [ngModel]="user.confirmEmail"
required validateEqual="email" reverse="false" #confirmEmail="ngModel"
pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$" placeHolder="Type Email"
[ngClass]="{'error-border': !(confirmEmail.valid || (confirmEmail.pristine && !f.submitted))}">
<small [hidden]="confirmEmail.valid || (confirmEmail.pristine && !f.submitted)" class="text-danger">
Wrong format or mismatch
</small>
<!--<pre *ngIf="confirmEmail.errors" class="margin-20">{{ confirmEmail.errors | json }}</pre>-->
</div>
<div class="form-group">
<input type="checkbox" class="form-control" name="confirmar" [ngModel]="user.conditions"
required #conditions="ngModel" (change)="user.conditions = !user.conditions">
<label for="">Accept terms and conditions</label>
</div>
<button type="submit"
class="btn btn-default"
[disabled]="!noEmail ?
!(user.conditions && email.valid && !email.pristine && confirmEmail.valid && !confirmEmail.pristine) :
!user.conditions">
Submit
</button>
<div class="margin-20" *ngIf="f">
<div>Form details:-</div>
<pre>Is form valid?: <br>{{f.valid | json}}</pre>
<pre>Is form submitted?: <br>{{f.submitted | json}}</pre>
<pre>submitted value: <br>{{f.value | json}}</pre>
</div>
</form>
</div>
.margin-20 {
margin-top: 20px;
}
.error-border {
border-style: solid;
border-color: red;
}
export interface Email {
bestEmail: string;
email: string;
confirmEmail: string;
conditions: boolean;
}
import { Directive, forwardRef, provide, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
provide(NG_VALIDATORS, { useExisting: forwardRef(() => EqualValidator), multi: true })
]
})
export class EqualValidator implements Validator {
constructor( @Attribute('validateEqual') public validateEqual: string,
@Attribute('reverse') public reverse: string) {
}
private get isReverse() {
if (!this.reverse) return false;
return this.reverse === 'true' ? true: false;
}
validate(c: AbstractControl): { [key: string]: any } {
// self value
let v = c.value;
// control vlaue
let e = c.root.find(this.validateEqual);
// value not equal
if (e && v !== e.value && !this.isReverse) {
return {
validateEqual: false
}
}
// value equal and reverse
if (e && v === e.value && this.isReverse) {
delete e.errors['validateEqual'];
if (!Object.keys(e.errors).length) e.setErrors(null);
}
// value not equal and reverse
if (e && v !== e.value && this.isReverse) {
e.setErrors({
validateEqual: false
})
}
return null;
}
}