### File

`src/lib/login/login.component.ts`

### Metadata

changeDetection | `ChangeDetectionStrategy.OnPush`
providers | `LoginFormProviders` `{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher, }`
selector | `rxap-login`
imports | `ReactiveFormsModule` `FormDirective` `MatIconModule` `MatFormFieldModule` `MatInputModule` `NgIf` `MatButtonModule` `MatCheckboxModule` `MatTooltipModule` `MatProgressSpinnerModule` `FormControlMarkDirtyDirective` `FormSubmitFailedDirective` `FormSubmittingDirective` `MatProgressBarModule` `AsyncPipe` `MatSnackBarModule` `ControlErrorDirective`
styleUrls | `./login.component.scss`
templateUrl | `./login.component.html`

### Index

###### Properties

- Public Readonly requestingPasswordReset$

###### Methods

- Public Async requestPasswordReset

### Constructor

`constructor(authentication: RxapAuthenticationService, snackBar: MatSnackBar)`
Defined in src/lib/login/login.component.ts:80

Parameters :

Name | Type | Optional
authentication | `RxapAuthenticationService` | No
snackBar | `MatSnackBar` | No

### Methods

Public Async requestPasswordReset
`requestPasswordReset(email: string)`
Defined in src/lib/login/login.component.ts:90

Parameters :

Name | Type | Optional
email | `string` | No

Returns : `any`

### Properties

Public Readonly requestingPasswordReset$
Default value : `new ToggleSubject()`
Defined in src/lib/login/login.component.ts:78

    import {
      AsyncPipe,
      NgIf,
    } from '@angular/common';
    import {
      ChangeDetectionStrategy,
      Component,
      inject,
      Inject,
    } from '@angular/core';
    import { ReactiveFormsModule } from '@angular/forms';
    import { MatButtonModule } from '@angular/material/button';
    import { MatCheckboxModule } from '@angular/material/checkbox';
    import {
      ErrorStateMatcher,
      ShowOnDirtyErrorStateMatcher,
    } from '@angular/material/core';
    import { MatFormFieldModule } from '@angular/material/form-field';
    import { MatIconModule } from '@angular/material/icon';
    import { MatInputModule } from '@angular/material/input';
    import { MatProgressBarModule } from '@angular/material/progress-bar';
    import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
    import {
      MatSnackBar,
      MatSnackBarModule,
    } from '@angular/material/snack-bar';
    import { MatTooltipModule } from '@angular/material/tooltip';
    import { RxapAuthenticationService } from '@rxap/authentication';
    import {
      FormControlMarkDirtyDirective,
      FormDirective,
      FormSubmitFailedDirective,
      FormSubmittingDirective,
    } from '@rxap/forms';
    import { ControlErrorDirective } from '@rxap/material-form-system';
    import { ToggleSubject } from '@rxap/rxjs';
    import { fadeAnimation } from '../fade-animation';
    import { LoginFormProviders } from './login.form';
    import { RequestResetPasswordMethod } from './request-reset-password.method';

    @Component({
        selector: 'rxap-login',
        templateUrl: './login.component.html',
        styleUrls: ['./login.component.scss'],
        changeDetection: ChangeDetectionStrategy.OnPush,
        providers: [
            LoginFormProviders,
            {
                provide: ErrorStateMatcher,
                useClass: ShowOnDirtyErrorStateMatcher,
            },
        ],
        animations: [
            fadeAnimation,
        ],
        imports: [
            ReactiveFormsModule,
            FormDirective,
            MatIconModule,
            MatFormFieldModule,
            MatInputModule,
            NgIf,
            MatButtonModule,
            MatCheckboxModule,
            MatTooltipModule,
            MatProgressSpinnerModule,
            FormControlMarkDirtyDirective,
            FormSubmitFailedDirective,
            FormSubmittingDirective,
            MatProgressBarModule,
            AsyncPipe,
            MatSnackBarModule,
            ControlErrorDirective,
        ]
    })
    export class LoginComponent {

      public readonly requestingPasswordReset$ = new ToggleSubject();

      private readonly requestPasswordResetMethod = inject(RequestResetPasswordMethod);

      constructor(
        @Inject(RxapAuthenticationService)
        private readonly authentication: RxapAuthenticationService,
        @Inject(MatSnackBar)
        private readonly snackBar: MatSnackBar,
      ) {
      }

      public async requestPasswordReset(email: string) {
        this.requestingPasswordReset$.enable();
        try {
          const result = await this.requestPasswordResetMethod.call({ email });

          if (!result) {
            this.snackBar.open(
              'The password reset request result is falsy',
              undefined,
              {
                duration: 5000,
                panelClass: 'error',
              },
            );
          } else {
            this.snackBar.open(
              'The password reset request was successful',
              undefined,
              {
                duration: 3000,
              },
            );
          }

        } catch (e: any) {
          this.snackBar.open(
            e.message,
            undefined,
            {
              duration: 3000,
              panelClass: 'error',
            },
          );
        } finally {
          this.requestingPasswordReset$.disable();
        }

      }
    }

    <form #form="rxapForm" [@fadeAnimation]="'in'"
          class="inner mat-elevation-z5 flex flex-col justify-center items-center gap-4"
          novalidate
          rxapForm>

      <div class="header flex flex-col items-center justify-center grow-0">

        <mat-icon class="avatar-icon grow-0" color="primary">account_circle</mat-icon>

      </div>

      <div class="content flex flex-col gap-8">

        <div class="flex flex-col">

          <mat-form-field class="email-input">
            <mat-icon inline matPrefix>email</mat-icon>
            <mat-label i18n>Email</mat-label>
            <input formControlName="email"
                   i18n-placeholder
                   matInput
                   name="email"
                   placeholder="Enter your email address"
                   type="email">
            <mat-error *rxapControlError="let error key 'required'">
              Email is <strong>required</strong>
            </mat-error>
            <mat-error *rxapControlError="let error key 'email'">
              Please enter a valid email address
            </mat-error>
          </mat-form-field>

          <mat-form-field class="password-input">
            <mat-icon inline matPrefix>vpn_key</mat-icon>
            <mat-label i18n>Password</mat-label>
            <input #passwordInput
                   formControlName="password"
                   i18n-placeholder
                   matInput
                   name="password"
                   placeholder="Enter your password"
                   type="password">
            <mat-error *rxapControlError="let error key 'required'">
              Password is <strong>required</strong>
            </mat-error>
            <button (click)="passwordInput.type = 'test'" *ngIf="passwordInput.type === 'password'" mat-icon-button
                    matSuffix tabIndex="-1"
                    type="button">
              <mat-icon>visibility</mat-icon>
            </button>
            <button (click)="passwordInput.type = 'password'" *ngIf="passwordInput.type === 'text'" mat-icon-button
                    matSuffix tabIndex="-1"
                    type="button">
              <mat-icon>visibility_off</mat-icon>
            </button>
          </mat-form-field>

        </div>

        <div class="sub-controls flex flex-row flex-wrap justify-between items-center gap-4">

          <mat-checkbox class="remember-input grow-0" formControlName="remember">Remember me</mat-checkbox>

          <div [matTooltipDisabled]="form.control.controls['email'].valid"
               class="grow-0"
               matTooltip="Please enter a valid email address"
               matTooltipPosition="above">
            <button (click)="requestPasswordReset(form.value.email)"
                    [disabled]="!form.value.email || form.control.controls['email'].hasError('email')"
                    color="accent"
                    mat-button
                    type="button">
                <span class="flex flex-row justify-between items-center gap-2">
                  <mat-progress-spinner *ngIf="requestingPasswordReset$ | async" [diameter]="15"
                                        mode="indeterminate"></mat-progress-spinner>
                  <span class="grow-0">Password forgotten</span>
                </span>
            </button>
          </div>

        </div>

        <div class="grow-0 flex flex-row justify-center items-center">

          <div class="grow-0">
            <button color="primary" mat-raised-button rxapFormControlMarkDirty type="submit">Login</button>
          </div>

        </div>

      </div>

      <div *rxapFormSubmitFailed="let error" class="flex flex-row justify-center items-center">
        <mat-error>{{ error.message }}</mat-error>
      </div>

      <mat-progress-bar *rxapFormSubmitting class="loading-bar" mode="indeterminate"></mat-progress-bar>

    </form>

`./login.component.scss`

    $padding: 48px;

    ::ng-deep .mat-mdc-snack-bar-container.error {
      background-color: var(--warn-500);
      color: var(--foreground-color);
    }

    .inner {
      padding: $padding;
      position: relative;
      margin: 16px 0;
      background-color: var(--background-color);

      ::ng-deep .mat-mdc-form-field-icon-prefix, ::ng-deep .mat-mdc-form-field-icon-suffix {
        color: var(--hint-text-color, gray);
      }

      .header {

        .avatar-icon {
          width: 100px;
          height: 100px;
          font-size: 100px;
        }

      }

      .content {
        width: 256px + $padding;
        max-width: calc(100vw - #{$padding * 2} - 16px);

        .email-input, .password-input {
          width: 100%;

          .prefix-icon {
            width: 24px;
            height: 24px;
            display: flex;
            justify-content: center;
            align-items: center;
          }

          /* TODO(mdc-migration): The following rule targets internal classes of form-field that may no longer apply for the MDC version. */
          ::ng-deep .mat-form-field-prefix {
            align-self: flex-end;
            margin: 4px;
          }

        }

        [type="submit"] {
          width: 128px;
          text-transform: uppercase;
        }

      }

      .sub-controls > * {
        margin-bottom: 8px;
      }

      .loading-bar {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        top: auto;
      }

    }

Legend
Html element
Component
Html element with directive

# results matching ""

# No results matching ""