Skip to content

Commit

Permalink
fix(primeng/p-password): incorrect class assignment for true value …
Browse files Browse the repository at this point in the history
…of `toggleMask` in the password component. (#11416)

The problem appeared during fix of the bug #10716 (running `detectChanges` in `pInputText`). Setter has been ran by detector without running doCheck inside `ngClass`.

Fixes #11356, #11408.

Co-authored-by: mertsincan <sincan.mert@gmail.com>
  • Loading branch information
volvachev and mertsincan committed Nov 8, 2022
1 parent 428d0c9 commit ce1ad29
Showing 1 changed file with 42 additions and 74 deletions.
116 changes: 42 additions & 74 deletions src/app/components/password/password.ts
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,33 +1,11 @@
import {
NgModule,
Directive,
ElementRef,
HostListener,
Input,
OnDestroy,
DoCheck,
NgZone,
OnInit,
ViewEncapsulation,
ChangeDetectionStrategy,
ContentChildren,
QueryList,
TemplateRef,
Component,
AfterContentInit,
ViewChild,
ChangeDetectorRef,
forwardRef,
Output,
EventEmitter
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { animate, style, transition, trigger } from '@angular/animations';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { DomHandler, ConnectedOverlayScrollHandler } from 'primeng/dom';
import { OverlayService, PrimeNGConfig, PrimeTemplate, TranslationKeys, SharedModule } from 'primeng/api';
import { ZIndexUtils } from 'primeng/utils';
import { InputTextModule } from 'primeng/inputtext';
import {NgModule,Directive,ElementRef,HostListener,Input,OnDestroy,DoCheck,NgZone, OnInit, ViewEncapsulation, ChangeDetectionStrategy, ContentChildren, QueryList, TemplateRef, Component, AfterContentInit, ViewChild, ChangeDetectorRef, forwardRef, Output, EventEmitter, Pipe, PipeTransform} from '@angular/core';
import {CommonModule} from '@angular/common';
import {animate, style, transition, trigger} from '@angular/animations';
import {NG_VALUE_ACCESSOR} from '@angular/forms';
import {DomHandler, ConnectedOverlayScrollHandler} from 'primeng/dom';
import {OverlayService, PrimeNGConfig, PrimeTemplate, TranslationKeys, SharedModule} from 'primeng/api';
import {ZIndexUtils} from 'primeng/utils';
import {InputTextModule} from 'primeng/inputtext';
import { Subscription } from 'rxjs';

@Directive({
Expand Down Expand Up @@ -256,6 +234,18 @@ export class PasswordDirective implements OnDestroy, DoCheck {
}
}

type Mapper<T, G> = (item: T, ...args: any[]) => G;

@Pipe({
name: 'mapper',
pure: true
})
export class MapperPipe implements PipeTransform {
public transform<T, G>(value: T, mapper: Mapper<T, G>, ...args: unknown[]): G {
return mapper(value, ...args);
}
}

export const Password_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Password),
Expand All @@ -264,46 +254,20 @@ export const Password_VALUE_ACCESSOR: any = {
@Component({
selector: 'p-password',
template: `
<div [ngClass]="containerClass()" [ngStyle]="style" [class]="styleClass">
<input
#input
[attr.label]="label"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledBy]="ariaLabelledBy"
[attr.id]="inputId"
pInputText
[ngClass]="inputFieldClass()"
[ngStyle]="inputStyle"
[class]="inputStyleClass"
[attr.type]="inputType()"
[attr.placeholder]="placeholder"
[value]="value"
(input)="onInput($event)"
(focus)="onInputFocus($event)"
(blur)="onInputBlur($event)"
(keyup)="onKeyUp($event)"
(keydown)="onKeyDown($event)"
/>
<div [ngClass]="toggleMask | mapper: containerClass" [ngStyle]="style" [class]="styleClass">
<input #input [attr.label]="label" [attr.aria-label]="ariaLabel" [attr.aria-labelledBy]="ariaLabelledBy" [attr.id]="inputId" pInputText [ngClass]="disabled | mapper: inputFieldClass" [ngStyle]="inputStyle" [class]="inputStyleClass" [attr.type]="unmasked | mapper: inputType" [attr.placeholder]="placeholder" [value]="value" (input)="onInput($event)" (focus)="onInputFocus($event)"
(blur)="onInputBlur($event)" (keyup)="onKeyUp($event)" (keydown)="onKeyDown($event)" />
<i *ngIf="showClear && value != null" class="p-password-clear-icon pi pi-times" (click)="clear()"></i>
<i *ngIf="toggleMask" [ngClass]="toggleIconClass()" (click)="onMaskToggle()"></i>
<div
#overlay
*ngIf="overlayVisible"
[ngClass]="'p-password-panel p-component'"
(click)="onOverlayClick($event)"
[@overlayAnimation]="{ value: 'visible', params: { showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions } }"
(@overlayAnimation.start)="onAnimationStart($event)"
(@overlayAnimation.done)="onAnimationEnd($event)"
[ngStyle]="panelStyle"
[class]="panelStyleClass"
>
<i *ngIf="toggleMask" [ngClass]="unmasked | mapper: toggleIconClass" (click)="onMaskToggle()"></i>
<div #overlay *ngIf="overlayVisible" [ngClass]="'p-password-panel p-component'" (click)="onOverlayClick($event)"
[@overlayAnimation]="{value: 'visible', params: {showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions}}" (@overlayAnimation.start)="onAnimationStart($event)" (@overlayAnimation.done)="onAnimationEnd($event)">
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
<ng-container *ngIf="contentTemplate; else content">
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
</ng-container>
<ng-template #content>
<div class="p-password-meter">
<div [ngClass]="strengthClass()" [ngStyle]="{ width: meter ? meter.width : '' }"></div>
<div [ngClass]="meter | mapper: strengthClass" [ngStyle]="{'width': meter ? meter.width : ''}"></div>
</div>
<div className="p-password-info">{{ infoText }}</div>
</ng-template>
Expand Down Expand Up @@ -660,20 +624,24 @@ export class Password implements AfterContentInit, OnInit {
}
}

containerClass() {
return { 'p-password p-component p-inputwrapper': true, 'p-input-icon-right': this.toggleMask };
containerClass(toggleMask: boolean) {
return {'p-password p-component p-inputwrapper': true,
'p-input-icon-right': toggleMask
};
}

inputFieldClass() {
return { 'p-password-input': true, 'p-disabled': this.disabled };
inputFieldClass(disabled: boolean) {
return {'p-password-input' : true,
'p-disabled': disabled
};
}

toggleIconClass() {
return this.unmasked ? 'pi pi-eye-slash' : 'pi pi-eye';
toggleIconClass(unmasked: boolean) {
return unmasked ? 'pi pi-eye-slash' : 'pi pi-eye';
}

strengthClass() {
return `p-password-strength ${this.meter ? this.meter.strength : ''}`;
strengthClass(meter: any) {
return `p-password-strength ${meter ? meter.strength : ''}`;
}

filled() {
Expand Down Expand Up @@ -703,8 +671,8 @@ export class Password implements AfterContentInit, OnInit {
}
}

inputType() {
return this.unmasked ? 'text' : 'password';
inputType(unmasked: boolean) {
return unmasked ? 'text' : 'password';
}

getTranslation(option: string) {
Expand Down Expand Up @@ -741,6 +709,6 @@ export class Password implements AfterContentInit, OnInit {
@NgModule({
imports: [CommonModule, InputTextModule],
exports: [PasswordDirective, Password, SharedModule],
declarations: [PasswordDirective, Password]
declarations: [PasswordDirective, Password, MapperPipe]
})
export class PasswordModule {}

0 comments on commit ce1ad29

Please sign in to comment.