MATERIAL LOGIN CARD


1. Antes de agregar el componente login necesitaremos de crear 1 directiva, en la siguiente ruta src/app/core/directives con el siguiente comando:

$ ng g d core/directives/responsive-rows --spec=false 

Angular 9
$ ng g d core/directives/responsive-rows --skipTests

A) responsive-rows.directive.ts
     Esta directiva nos permitira crear grillas para formularios similar al bootstrap.
     Previamente a moficar el codigo necesitamos instalar una libreria adicional:
   
     $ npm install --save @angular/flex-layout@7.0.0-beta.24
     Angular 9
     $ npm install --save @angular/flex-layout@9.0.0-beta.29

import { DirectiveOnInitInput } from '@angular/core';
import { MatGridTile } from '@angular/material';
import { MediaObserverMediaChange } from '@angular/flex-layout';

export interface IResponsiveRowsMap {
  xs?: number;
  sm?: number;
  md?: number;
  lg?: number;
  xl?: number;
}

@Directive({
  selector: '[ResponsiveRows]'
})
export class ResponsiveRowsDirective implements OnInit {
  private countBySizeIResponsiveRowsMap = { xs: 2sm: 2md: 4lg: 6xl: 8 };

  public get colspan(): IResponsiveRowsMap {
    return this.countBySize;
  }

  @Input('ResponsiveRows')
  public set colspan(mapIResponsiveRowsMap) {
    if (map && ('object' === (typeof map))) {
      this.countBySize = map;
    }
  }

  public constructor(private gridMatGridTileprivate serviceMediaMediaObserver) {
    this.initializeRowsCount();
  }

  public ngOnInit(): void {
    this.initializeRowsCount();
    this.serviceMedia.media$.subscribe((changesMediaChange=> {
        this.grid.colspan = this.countBySize[changes.mqAlias]
      });
  }

  private initializeRowsCount(): void {
    Object.keys(this.countBySize).some(
      (mqAliasstring): boolean => {
        const isActive = this.serviceMedia.isActive(mqAlias);
        if (isActive) {
          this.grid.colspan = this.countBySize[mqAlias];
        }
        return isActive;
      });
  }
}

2. Seguido necesitaremos crear una clase, en la siguiente ruta src/app/core/model con el siguiente comando:

$ ng g i core/model/usuario

A) usuario.model.ts
     Esta clase nos permitira guardar los datos de usuario y contraseña para la autenticacion.

export class Usuario {
    usuariostring;
    contraseniastring;
}

3. Luego necesitaremos crear 2 servicios, en la siguiente ruta src/app/core/services con el siguiente comando:

$ ng g s core/services/usuario --spec=false
$ ng g s core/services/validation --spec=false

A) usuario.service.ts
     Este servicio nos permitira mantener los datos en la sesion:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UsuarioService {
  idnumber;
  usuariostring;
  contraseniastring;
  idCargonumber;
  cargostring;
  idDependencianumber;
  dependenciastring;

  constructor() { }

  set setId(idnumber) { this.id = id; }
  set setUsuario(usuariostring) { this.usuario = usuario; }
  set setContrasenia(contraseniastring) { this.contrasenia = contrasenia; }
  set setIdCargo(idCargonumber) { this.idCargo = idCargo; }
  set setCargo(cargostring) { this.cargo = cargo; }
  set setIdDependencia(idDependencianumber) { this.idDependencia = idDependencia; }
  set setDependencia(dependenciastring) { this.dependencia = dependencia; }

  get getId() { return this.id; }
  get getUsuario() { return this.usuario; }
  get getContrasenia() { return this.contrasenia; }
  get getIdCargo() { return this.idCargo; }
  get getCargo() { return this.cargo; }
  get getIdDependencia() { return this.idDependencia; }
  get getDependencia() { return this.dependencia; }

  public limpiarRegistro(): void {
    this.id = null;
    this.usuario = null;
    this.contrasenia = null;
    this.idCargo = null;
    this.cargo = null;
    this.idDependencia = null;
    this.dependencia = null;
    return null;
  }
}

B) validation.service.ts
     Este servicio nos permitir hacer operaciones de validacion de formularios.

import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Injectable({
  providedIn: 'root'
})
export class ValidationService {
  constructor() { }

  getValidationErrors(groupFormGroupmessagesanyformErrorsanytypeboolean): void {
    Object.keys(group.controls).forEach((keystring=> {
      let abstractControl = group.get(key);
      if (abstractControl instanceof FormGroup) {
        this.getValidationErrors(abstractControlmessages[key], formErrors[key], type);
      } else {
        if (type) {
          abstractControl.markAsTouched();
        }
        formErrors[key] = '';
        if (abstractControl && abstractControl.invalid && (abstractControl.touched || abstractControl.dirty)) {
          let msg = messages[key];
          for (let errorKey in abstractControl.errors) {
            if (errorKey) {
              formErrors[key] += msg[errorKey] + ' ';
            }
          }
        }
      }
    });
  }

  setAsUntoched(groupFormGroupformErrorsanyexclusions?: string[]): void {
    group.markAsUntouched();
    Object.keys(group.controls).forEach((keystring=> {
      let abstractControl = group.get(key);
      if (abstractControl instanceof FormGroup) {
        this.setAsUntoched(abstractControlformErrors[key]);
      } else {
        if (typeof exclusions != 'undefined') {
          let ex = exclusions.find(el => el == key);
          if (!ex) {
            abstractControl.setValue('');
            abstractControl.markAsUntouched();
          }
        } else {
          abstractControl.setValue('');
          abstractControl.markAsUntouched();
        }
        formErrors[key] = '';
      }
    });
  }

  disableControls(groupFormGroupexclusions?: [string]): void {
    Object.keys(group.controls).forEach((keystring=> {
      let abstractControl = group.get(key);
      if (abstractControl instanceof FormGroup) {
        this.disableControls(abstractControlexclusions);
      } else {
        if (typeof exclusions != 'undefined') {
          let ex = exclusions.find(el => el == key);
          if (!ex) {
            abstractControl.disable()
          }
        } else {
          abstractControl.disable();
        }
      }
    });
  }

  removeErrors(groupFormGroupexclusions?: [string]): void {
    Object.keys(group.controls).forEach((keystring=> {
      let abstractControl = group.get(key);
      if (abstractControl instanceof FormGroup) {
        this.removeErrors(abstractControlexclusions);
      } else {
        if (typeof exclusions != 'undefined') {
          let ex = exclusions.find(el => el == key);
          if (!ex) {
            abstractControl.setErrors(null)
          }
        } else {
          abstractControl.setErrors(null);
        }
      }
    });
  }
}

4. Para agregar un login es necesario crear un componente con nombre login en la siguiente ruta src/app/modules/sesion/comonents/login

A) login.component.html

<mat-card class="login-card">
  <mat-card-header>
    <mat-card-title>
      <div mat-card-avatar class="login-card-header-image"></div>
    </mat-card-title>
  </mat-card-header>
  <mat-card-content>
    <h3>Ingresa a tu cuenta</h3>
    <form [formGroup]="formularioGrp">
      <mat-grid-list cols="12" rowHeight="50px">
        <mat-grid-tile [ResponsiveRows]="{xs:12, sm:12, md:12, lg:12, xl:12}">
          <mat-form-field>
            <input matInput formControlName="usuario" type="text" id="usuario" placeholder="Inserte su ID de usuario"
              [ngClass]="{'is-invalid': formErrors.usuario}" (keyup.enter)="autenticar()">
          </mat-form-field>
        </mat-grid-tile>
        <mat-grid-tile [ResponsiveRows]="{xs:12, sm:12, md:12, lg:12, xl:12}">
          <mat-form-field>
            <input matInput formControlName="contrasenia" type="password" id="contrasenia"
              placeholder="Inserte su contraseña" [ngClass]="{'is-invalid': formErrors.contrasenia}"
              (keyup.enter)="autenticar()">
          </mat-form-field>
        </mat-grid-tile>
        <mat-grid-tile [ResponsiveRows]="{xs:12, sm:12, md:12, lg:12, xl:12}">
          <mat-checkbox>Recordar</mat-checkbox>
        </mat-grid-tile>
        <mat-grid-tile [ResponsiveRows]="{xs:12, sm:12, md:12, lg:12, xl:12}">
          <button mat-raised-button color="primary" (click)="autenticar()">Ingresar</button>
        </mat-grid-tile>
      </mat-grid-list>
    </form>
  </mat-card-content>
</mat-card>

B) login.component.ts

import { ComponentOnInitInject } from '@angular/core';
import { Usuario } from 'src/app/core/model/usuario.model';
import { FormGroupFormBuilderValidators } from '@angular/forms';
import { Router } from '@angular/router';
import { UsuarioService } from 'src/app/core/services/usuario.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
  usuarioUsuario = new Usuario();
  formularioGrpFormGroup;

  messages = {
    'usuario': {
      'required': 'El campo es obligatorio'
    },
    'contrasenia': {
      'required': 'El campo es obligatorio'
    }
  };
  formErrors = {
    'usuario': '',
    'contrasenia': '',
  };

  constructor(private fbFormBuilderprivate routerRouter, @Inject(UsuarioServiceprivate userUsuarioService) { }

  ngOnInit() {
    this.formularioGrp = this.fb.group({
      usuario: ['', [Validators.required]],
      contrasenia: ['', [Validators.required]],
    });

    this.formularioGrp.get('usuario').setValue('admin');
    this.formularioGrp.get('contrasenia').setValue('1234');
  }

  autenticar() {
    this.usuario.usuario = this.formularioGrp.get('usuario').value;
    this.usuario.contrasenia = this.formularioGrp.get('contrasenia').value;

    localStorage.setItem('user'JSON.stringify(this.usuario));
    this.user.setId = 1;
    this.user.setUsuario = this.usuario.usuario;
    this.user.setContrasenia = this.usuario.contrasenia;
    this.user.setCargo = 'TECNICO INFORMATICO';
    this.user.setDependencia = 'UTI';

    this.router.navigate(['/intranet/home']);
  }
}

C) login.component.scss

.login-card {
    margin10% auto 0%;
    width300px;
    max-width300px;
    text-aligncenter;
    box-shadow0px 0px 10px 2px #888888;
    mat-card-header {
        displayflex !important;
        justify-contentcenter !important;
    }
    form {
        mat-grid-tile {
            button {
                width90%;
            }
        }
    }

}

::ng-deep .login-card-header-image {
  background-imageurl("../../../../../assets/images/icons/icono-perficon.png");
  background-sizecover;
  height60px !important;
  width60px !important;
}

mat-checkbox {
  padding-left10px;
}

5. Finalmente agregamos algunos componenentes necesarios en el archivo material.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModuleMatToolbarModuleMatSidenavModuleMatMenuModuleMatCardModuleMatGridListModuleMatInputModuleMatListModuleMatCheckboxModule } from '@angular/material';
import { ResponsiveRowsDirective } from '../core/directives/responsive-rows.directive';
import { UppercasedDirective } from '../core/directives/uppercased.directive';
import { ReactiveFormsModule } from '@angular/forms';
import { LayoutModule } from '@angular/cdk/layout';

@NgModule({
  declarations: [
    ResponsiveRowsDirective,
    UppercasedDirective,
  ],
  imports: [
    ReactiveFormsModule,
    CommonModule,
    LayoutModule,
    
    MatButtonModule,
    MatToolbarModule,
    MatSidenavModule,
    MatMenuModule,
    MatCardModule,
    MatGridListModule,
    MatListModule,
    MatInputModule,
    MatCheckboxModule,
  ],
  exports: [
    ReactiveFormsModule,
    LayoutModule,

    MatButtonModule,
    MatToolbarModule,
    MatSidenavModule,
    MatMenuModule,
    MatCardModule,
    MatGridListModule,
    MatListModule,
    MatInputModule,
    MatCheckboxModule,

    ResponsiveRowsDirective,
    UppercasedDirective,
  ]
})
export class MaterialModule { }