Skip to content

Commit ea442b1

Browse files
author
Jagan Mohan Bishoyi
committed
1. Tempate type added - 'inline' | 'popup', Default 'popup'
2. Now only able to pass options using [NgPasswordValidator] to minimize complexity. 3. Performance optimizations
1 parent 45ccee8 commit ea442b1

File tree

10 files changed

+107
-81
lines changed

10 files changed

+107
-81
lines changed

projects/ng-password-validator-dev/src/app/app.component.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
</div>
77

88
<div class="content" role="main">
9-
<input type="text" id="password" name="password" placeholder="Password.." [NgPasswordValidator]="options">
9+
<input type="text" id="password" name="password" placeholder="Password.." [NgPasswordValidator]="options"
10+
(valid)="isValid($event)">
11+
<input type="text" name="password" placeholder="Password..">
12+
<input type="text" name="password" placeholder="Password..">
13+
<input type="text" name="password" placeholder="Password..">
14+
<input type="text" name="password" placeholder="Password..">
1015
<!-- <input type="text" id="password" name="password" placeholder="Password.." NgPasswordValidator> -->
1116
</div>
1217

projects/ng-password-validator-dev/src/app/app.component.scss

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,34 @@ p {
5252

5353
.content {
5454
display: flex;
55-
margin: 82px auto 32px;
55+
margin: 150px auto 32px;
5656
padding: 0 16px;
5757
max-width: 960px;
5858
flex-direction: column;
5959
align-items: center;
6060

6161
input {
6262
width: 400px;
63-
margin-top: 60px;
6463
font-size: max(16px, 1em);
6564
font-family: inherit;
6665
padding: 0.25em 0.5em;
6766
background-color: #fff;
6867
border: 2px solid #eeeeee;
6968
border-radius: 4px;
7069
height: 28px;
70+
margin-bottom: 15px;
71+
}
72+
}
73+
74+
::ng-deep {
75+
.custom-class {
76+
.popup-window {
77+
padding: 0;
78+
79+
.heading {
80+
color: #9c0404;
81+
font-family: inherit;
82+
}
83+
}
7184
}
7285
}

projects/ng-password-validator-dev/src/app/app.component.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Component } from '@angular/core';
2+
import { NgPasswordValidatorOptions } from 'projects/ng-password-validator/src/lib/ng-password-validator.interface';
23

34
@Component({
45
selector: 'app-root',
@@ -7,8 +8,10 @@ import { Component } from '@angular/core';
78
})
89
export class AppComponent {
910
title = 'ng-password-validator-dev';
10-
options = {
11+
options: NgPasswordValidatorOptions = {
1112
placement: 'bottom',
13+
type: 'inline',
14+
'custom-class': 'custom-class',
1215
rules: {
1316
password: {
1417
type: 'range',
@@ -19,4 +22,8 @@ export class AppComponent {
1922
shadow: true,
2023
offset: 15,
2124
};
25+
26+
isValid(event: boolean): void {
27+
console.log(event);
28+
}
2229
}

projects/ng-password-validator/src/lib/ng-password-validator.component.scss

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
.popup-window {
3333
.heading {
3434
font-size: $heading-font-size;
35-
color: $black;
3635
margin-bottom: 0.5rem;
3736
font-weight: 700;
3837
}
@@ -97,6 +96,4 @@
9796
}
9897
}
9998
}
100-
101-
10299
}

projects/ng-password-validator/src/lib/ng-password-validator.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,9 @@ export class NgPasswordValidatorComponent implements OnInit, OnChanges {
324324
setStyles(): void {
325325
this.setZIndex();
326326
this.setAnimationDuration();
327-
328-
this.hostClassShadow = this.options['shadow'];
327+
if (this.options.type !== 'inline') {
328+
this.hostClassShadow = this.options['shadow'];
329+
}
329330
this.hostStyleMaxWidth = this.options['max-width'] + 'px';
330331
this.hostStyleWidth = this.options['width']
331332
? this.options['width'] + 'px'

projects/ng-password-validator/src/lib/ng-password-validator.directive.ts

Lines changed: 35 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,14 @@ import { Subscription } from 'rxjs';
2020
import { DataService } from './data.service';
2121
import { NgPasswordValidatorComponent } from './ng-password-validator.component';
2222
import {
23+
HostComponent,
2324
IElementPosition,
2425
IPosition,
2526
NgPasswordValidatorOptions,
2627
} from './ng-password-validator.interface';
2728
import { NgPasswordValidatorService } from './ng-password-validator.service';
2829
import { defaultOptions } from './options';
29-
30-
export interface HostComponent {
31-
data: any;
32-
show: boolean;
33-
close: boolean;
34-
events: any;
35-
}
30+
import { UtilsService } from './utils.service';
3631

3732
@Directive({
3833
selector: '[NgPasswordValidator]',
@@ -52,25 +47,7 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
5247
passwordOptions: NgPasswordValidatorOptions;
5348
componentSubscribe: Subscription;
5449

55-
@Input('options') set optionsInput(value: NgPasswordValidatorOptions) {
56-
if (value && defaultOptions) {
57-
this.passwordOptions = this.deepMerge(defaultOptions, value);
58-
this.createPasswordRegex();
59-
}
60-
}
6150
@Input('NgPasswordValidator') popup: NgPasswordValidatorOptions;
62-
@Input('placement') placement: string;
63-
@Input('z-index') zIndex: number;
64-
@Input('animation-duration') animationDuration: number;
65-
@Input('custom-class') customClass: string;
66-
@Input('shadow') shadow: boolean;
67-
@Input('theme') theme: 'basic' | 'pro';
68-
@Input('offset') offset: number;
69-
@Input('width') width: number;
70-
@Input('max-width') maxWidth: number;
71-
@Input('position') position: IPosition;
72-
@Input('heading') heading: string;
73-
@Input('successMessage') successMessage: string;
7451

7552
@Output() events: EventEmitter<any> = new EventEmitter<any>();
7653
@Output() valid: EventEmitter<boolean> = new EventEmitter();
@@ -81,6 +58,7 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
8158
private componentFactoryResolver: ComponentFactoryResolver,
8259
private appRef: ApplicationRef,
8360
private dataService: DataService,
61+
private utilsService: UtilsService,
8462
private injector: Injector
8563
) {}
8664

@@ -92,13 +70,6 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
9270
return this.componentRef && this.componentRef.hostView.destroyed;
9371
}
9472

95-
/**
96-
* Get popup position
97-
*
98-
* @readonly
99-
* @type {(IElementPosition | IPosition)}
100-
* @memberof NgPasswordValidatorDirective
101-
*/
10273
get popupPosition(): IElementPosition | IPosition {
10374
if (this.options['position']) {
10475
return this.options['position'];
@@ -118,19 +89,6 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
11889
this.show();
11990
this.checkPassword(value);
12091
}
121-
/**
122-
* Update password options
123-
*
124-
* @memberof NgPasswordValidatorDirective
125-
*/
126-
updatePasswordOptions(): void {
127-
if (this.popup && defaultOptions) {
128-
this.passwordOptions = this.deepMerge(defaultOptions, this.popup);
129-
} else {
130-
this.passwordOptions = { ...defaultOptions };
131-
}
132-
this.createPasswordRegex();
133-
}
13492

13593
/**
13694
* Focus out of input field
@@ -139,7 +97,10 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
13997
*/
14098
@HostListener('focusout')
14199
onMouseLeave(): void {
142-
this.destroyPopup();
100+
// If the template type is inline, don't destroy the created template
101+
if (this.passwordOptions.type !== 'inline') {
102+
this.destroyPopup();
103+
}
143104
this.valid.emit(this.isValid);
144105
}
145106

@@ -161,6 +122,12 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
161122
* @memberof NgPasswordValidatorDirective
162123
*/
163124
ngOnChanges(changes: { popup: SimpleChange }): void {
125+
// If the template type is 'inline' create the inline template directly
126+
const templateType = changes.popup.currentValue.type;
127+
if (templateType === 'inline') {
128+
this.updatePasswordOptions();
129+
this.show();
130+
}
164131
const changedOptions = this.getProperties(changes);
165132
this.applyOptionsDefault(changedOptions, defaultOptions);
166133
}
@@ -177,31 +144,6 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
177144
}
178145
}
179146

180-
/**
181-
* Deep merge objects
182-
*
183-
* @param {NgPasswordValidatorOptions} target
184-
* @param {NgPasswordValidatorOptions} source
185-
* @returns {NgPasswordValidatorOptions}
186-
* @memberof NgPasswordValidatorDirective
187-
*/
188-
deepMerge(
189-
target: NgPasswordValidatorOptions,
190-
source: NgPasswordValidatorOptions
191-
): NgPasswordValidatorOptions {
192-
// Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
193-
for (const key of Object.keys(source)) {
194-
if (source[key] instanceof Object) {
195-
Object.assign(source[key], this.deepMerge(target[key], source[key]));
196-
}
197-
}
198-
199-
// Join `target` and modified `source`
200-
Object.assign(target || {}, source);
201-
202-
return target;
203-
}
204-
205147
/**
206148
* Create password regex
207149
*
@@ -273,6 +215,23 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
273215
this.dataService.updateValue(data);
274216
}
275217

218+
/**
219+
* Update password options
220+
*
221+
* @memberof NgPasswordValidatorDirective
222+
*/
223+
updatePasswordOptions(): void {
224+
if (this.popup && defaultOptions) {
225+
this.passwordOptions = this.utilsService.deepMerge(
226+
defaultOptions,
227+
this.popup
228+
);
229+
} else {
230+
this.passwordOptions = { ...defaultOptions };
231+
}
232+
this.createPasswordRegex();
233+
}
234+
276235
/**
277236
* Get properties
278237
*
@@ -400,6 +359,11 @@ export class NgPasswordValidatorDirective implements OnDestroy, OnChanges {
400359
).events.subscribe((event: any) => {
401360
this.handleEvents(event);
402361
});
362+
363+
if (this.options.type === 'inline') {
364+
this.elementRef.nativeElement.style.marginBottom =
365+
this.popupPosition['bottom'] + 'px';
366+
}
403367
}
404368

405369
/**

projects/ng-password-validator/src/lib/ng-password-validator.interface.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface NgPasswordValidatorOptions {
55
'custom-class'?: string;
66
shadow?: boolean;
77
theme?: 'basic' | 'pro';
8+
type?: 'inline' | 'popup';
89
offset?: number;
910
width?: number;
1011
'max-width'?: number;
@@ -48,3 +49,9 @@ export interface IStatus {
4849
'include-lowercase-characters': boolean;
4950
'include-uppercase-characters': boolean;
5051
}
52+
export interface HostComponent {
53+
data: any;
54+
show: boolean;
55+
close: boolean;
56+
events: any;
57+
}

projects/ng-password-validator/src/lib/ng-password-validator.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { NgPasswordValidatorComponent } from './ng-password-validator.component'
55
import { NgPasswordValidatorDirective } from './ng-password-validator.directive';
66
import { NgPasswordValidatorOptions } from './ng-password-validator.interface';
77
import { NgPasswordValidatorService } from './ng-password-validator.service';
8+
import { UtilsService } from './utils.service';
89

910
@NgModule({
1011
declarations: [NgPasswordValidatorDirective, NgPasswordValidatorComponent],
1112
imports: [CommonModule],
12-
providers: [DataService],
13+
providers: [DataService, UtilsService],
1314
exports: [NgPasswordValidatorDirective],
1415
entryComponents: [NgPasswordValidatorComponent],
1516
})

projects/ng-password-validator/src/lib/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const defaultOptions: NgPasswordValidatorOptions = {
99
'custom-class': '',
1010
shadow: true,
1111
theme: 'pro',
12+
type: 'popup',
1213
offset: 8,
1314
heading: 'Password Policy',
1415
successMessage: 'Awesome! Password requirement fulfilled.',
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Injectable } from '@angular/core';
2+
import { NgPasswordValidatorOptions } from './ng-password-validator.interface';
3+
4+
@Injectable()
5+
export class UtilsService {
6+
/**
7+
* Deep merge objects
8+
*
9+
* @param {NgPasswordValidatorOptions} target
10+
* @param {NgPasswordValidatorOptions} source
11+
* @returns {NgPasswordValidatorOptions}
12+
* @memberof UtilsService
13+
*/
14+
deepMerge(
15+
target: NgPasswordValidatorOptions,
16+
source: NgPasswordValidatorOptions
17+
): NgPasswordValidatorOptions {
18+
// Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
19+
for (const key of Object.keys(source)) {
20+
if (source[key] instanceof Object) {
21+
Object.assign(source[key], this.deepMerge(target[key], source[key]));
22+
}
23+
}
24+
25+
// Join `target` and modified `source`
26+
Object.assign(target || {}, source);
27+
28+
return target;
29+
}
30+
}

0 commit comments

Comments
 (0)