From 8dbbdadfe314986e3716f886dd6ffeb866527bc9 Mon Sep 17 00:00:00 2001 From: Zoriana Dombrovskij Date: Tue, 25 Sep 2018 17:31:41 +0200 Subject: [PATCH 1/2] feat(password input): Add the password input component and tests for it --- .../password-input.component.html | 7 ++ .../password-input.component.scss | 20 ++++ .../password-input.component.spec.ts | 52 +++++++++++ .../password-input.component.ts | 93 +++++++++++++++++++ .../password-input.module.spec.ts | 13 +++ .../password-input/password-input.module.ts | 11 +++ .../src/lib/ng-rocketparts.module.ts | 9 +- 7 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 projects/ng-rocketparts/src/lib/components/password-input/password-input.component.html create mode 100644 projects/ng-rocketparts/src/lib/components/password-input/password-input.component.scss create mode 100644 projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts create mode 100644 projects/ng-rocketparts/src/lib/components/password-input/password-input.component.ts create mode 100644 projects/ng-rocketparts/src/lib/components/password-input/password-input.module.spec.ts create mode 100644 projects/ng-rocketparts/src/lib/components/password-input/password-input.module.ts diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.html b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.html new file mode 100644 index 0000000..83e779b --- /dev/null +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.html @@ -0,0 +1,7 @@ + +
+ +
diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.scss b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.scss new file mode 100644 index 0000000..8120eb3 --- /dev/null +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.scss @@ -0,0 +1,20 @@ +.password-input { + padding: 0; + color: #696969; + position: relative; + display: flex; + align-items: center; + + input { + border: none; + padding-left: 35px; + text-align: center; + } + + .password-eye { + position: absolute; + flex: 1 1 auto; + cursor: pointer; + } +} + diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts new file mode 100644 index 0000000..0c2e435 --- /dev/null +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts @@ -0,0 +1,52 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PasswordInputComponent } from './password-input.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +describe('Component: PasswordInputComponent', () => { + let component: PasswordInputComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule], + declarations: [PasswordInputComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should change input type with a click on the icon', () => { + const element = fixture.nativeElement; + + expect(element.querySelector('input').type).toBe('password'); + + element.querySelector('i').click(); + fixture.detectChanges(); + expect(element.querySelector('input').type).toBe('text'); + + element.querySelector('i').click(); + fixture.detectChanges(); + expect(element.querySelector('input').type).toBe('password'); + }); + + it('should change an icon with a click on it', () => { + const element = fixture.nativeElement; + + expect(element.querySelector('i').classList).toContain('fa-eye'); + + element.querySelector('i').click(); + fixture.detectChanges(); + + expect(element.querySelector('i').classList).toContain('fa-eye-slash'); + + element.querySelector('i').click(); + fixture.detectChanges(); + + expect(element.querySelector('i').classList).toContain('fa-eye'); + }); +}); diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.ts b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.ts new file mode 100644 index 0000000..ae8b279 --- /dev/null +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.ts @@ -0,0 +1,93 @@ +import { + Component, + ElementRef, + forwardRef, + HostBinding, + Input, + OnInit +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; + +export const PASSWORD_INPUT_VALUE_ACCESSOR: any = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PasswordInputComponent), // tslint:disable-line + multi: true +}; + +@Component({ + selector: 'ngr-password-input', + templateUrl: './password-input.component.html', + styleUrls: ['./password-input.component.scss'], + providers: [PASSWORD_INPUT_VALUE_ACCESSOR] +}) +export class PasswordInputComponent implements OnInit, ControlValueAccessor { + @HostBinding('class.ngr-password-input') + passwordInputClass = true; + + @Input() + placeholder: string; + + @Input() + paddingLeft: number; + + onChange: () => void; + + onTouched: () => void; + + input: any; + + displayValue: string; + + disabled: boolean; + + show: boolean; + + constructor(private elem: ElementRef) {} + + ngOnInit() { + this.input = this.elem.nativeElement.querySelector('input'); + this.show = this.input.type === 'password'; + } + + registerOnChange(fn: any): void { + this.onChange = () => { + if (fn) { + fn(this.displayValue); + } + }; + } + + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: any): void { + if (this.displayValue !== value) { + this.displayValue = value; + } + } + + /** + * Called when the selection changed + * @param value + */ + onInputChange(value: string) { + this.displayValue = value; + if (this.onChange) { + this.onChange(); + } + } + + /** + * Allows to show and hide password + * @param {Event} e + */ + toggle(e: Event) { + this.show = !this.show; + this.input.type = this.input.type === 'password' ? 'text' : 'password'; + } +} diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.module.spec.ts b/projects/ng-rocketparts/src/lib/components/password-input/password-input.module.spec.ts new file mode 100644 index 0000000..51b30a9 --- /dev/null +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.module.spec.ts @@ -0,0 +1,13 @@ +import { PasswordInputModule } from './password-input.module'; + +describe('PasswordInputModule', () => { + let passwordInputModule: PasswordInputModule; + + beforeEach(() => { + passwordInputModule = new PasswordInputModule(); + }); + + it('should create an instance', () => { + expect(passwordInputModule).toBeTruthy(); + }); +}); diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.module.ts b/projects/ng-rocketparts/src/lib/components/password-input/password-input.module.ts new file mode 100644 index 0000000..bba4b41 --- /dev/null +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { PasswordInputComponent } from './password-input.component'; + +@NgModule({ + imports: [CommonModule, FormsModule, ReactiveFormsModule], + declarations: [PasswordInputComponent], + exports: [PasswordInputComponent] +}) +export class PasswordInputModule {} diff --git a/projects/ng-rocketparts/src/lib/ng-rocketparts.module.ts b/projects/ng-rocketparts/src/lib/ng-rocketparts.module.ts index 7944e05..97e301e 100644 --- a/projects/ng-rocketparts/src/lib/ng-rocketparts.module.ts +++ b/projects/ng-rocketparts/src/lib/ng-rocketparts.module.ts @@ -1,9 +1,14 @@ import { NgModule } from '@angular/core'; import { MaybeAsyncPipe } from './pipes/maybe-async.pipe'; +import { PasswordInputModule } from './components/password-input/password-input.module'; +import { CommonModule } from '@angular/common'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +const MODULES = [PasswordInputModule]; @NgModule({ - imports: [], + imports: [CommonModule, FormsModule, ReactiveFormsModule], declarations: [MaybeAsyncPipe], - exports: [MaybeAsyncPipe] + exports: [...MODULES, MaybeAsyncPipe] }) export class NgRocketPartsModule {} From ec15970d0b03cb3f9c7ebc65c31e940349d7eb9f Mon Sep 17 00:00:00 2001 From: Zoriana Dombrovskij Date: Tue, 25 Sep 2018 17:50:46 +0200 Subject: [PATCH 2/2] refactor: minor refactoring --- .../password-input/password-input.component.spec.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts index 0c2e435..da706fb 100644 --- a/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts +++ b/projects/ng-rocketparts/src/lib/components/password-input/password-input.component.spec.ts @@ -6,6 +6,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; describe('Component: PasswordInputComponent', () => { let component: PasswordInputComponent; let fixture: ComponentFixture; + let element: any; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -17,12 +18,11 @@ describe('Component: PasswordInputComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(PasswordInputComponent); component = fixture.componentInstance; + element = fixture.nativeElement; fixture.detectChanges(); }); it('should change input type with a click on the icon', () => { - const element = fixture.nativeElement; - expect(element.querySelector('input').type).toBe('password'); element.querySelector('i').click(); @@ -35,18 +35,14 @@ describe('Component: PasswordInputComponent', () => { }); it('should change an icon with a click on it', () => { - const element = fixture.nativeElement; - expect(element.querySelector('i').classList).toContain('fa-eye'); element.querySelector('i').click(); fixture.detectChanges(); - expect(element.querySelector('i').classList).toContain('fa-eye-slash'); element.querySelector('i').click(); fixture.detectChanges(); - expect(element.querySelector('i').classList).toContain('fa-eye'); }); });