File

angular/projects/researchdatabox/manage-users/src/app/manage-users.component.ts

Extends

BaseComponent

Metadata

Index

Properties
Methods

Constructor

constructor(loggerService: LoggerService, translationService: TranslationService, userService: UserService, _fb: FormBuilder)
Parameters :
Name Type Optional
loggerService LoggerService No
translationService TranslationService No
userService UserService No
_fb FormBuilder No

Methods

editUser
editUser(username: string)
Parameters :
Name Type Optional
username string No
Returns : void
genKey
genKey(userid: string)
Parameters :
Name Type Optional
userid string No
Returns : void
getNewUserFormControls
getNewUserFormControls()
Returns : {}
getNewUserPasswordErrors
getNewUserPasswordErrors()
Returns : {}
getNewUserPasswordFormControls
getNewUserPasswordFormControls()
Returns : any
getUpdateUserFormControls
getUpdateUserFormControls()
Returns : {}
getUpdateUserPasswordErrors
getUpdateUserPasswordErrors()
Returns : {}
hideDetailsModal
hideDetailsModal()
Returns : void
hideNewUserModal
hideNewUserModal()
Returns : void
Protected Async initComponent
initComponent()
Inherited from BaseComponent
Defined in BaseComponent:59
Returns : Promise<void>
isUpdateUserFormConfirmPasswordTouched
isUpdateUserFormConfirmPasswordTouched()
Returns : boolean
mapRoles
mapRoles(roles: any)
Parameters :
Name Type Optional
roles any No
Returns : any
newUser
newUser()
Returns : void
Async newUserSubmit
newUserSubmit(user: UserForm, isValid: boolean)
Parameters :
Name Type Optional
user UserForm No
isValid boolean No
Returns : any
onDetailsModalHidden
onDetailsModalHidden()
Returns : void
onFilterChange
onFilterChange()
Returns : void
onNewUserHidden
onNewUserHidden()
Returns : void
Async refreshUsers
refreshUsers()
Returns : any
resetFilter
resetFilter()
Returns : void
revokeKey
revokeKey(userid: string)
Parameters :
Name Type Optional
userid string No
Returns : void
setNewUserMessage
setNewUserMessage(msg: any, type: string)
Parameters :
Name Type Optional Default value
msg any No undefined
type string No 'primary'
Returns : void
setUpdateMessage
setUpdateMessage(msg: any, type: string)
Parameters :
Name Type Optional Default value
msg any No undefined
type string No 'primary'
Returns : void
setupForms
setupForms(newUser: boolean)
Parameters :
Name Type Optional
newUser boolean No
Returns : void
showDetailsModal
showDetailsModal()
Returns : void
showNewUserModal
showNewUserModal()
Returns : void
Async updateUserSubmit
updateUserSubmit(user: UserForm, isValid: boolean)
Parameters :
Name Type Optional
user UserForm No
isValid boolean No
Returns : any
getInitSubject
getInitSubject()
Inherited from BaseComponent
Defined in BaseComponent:71

For those interested in the init from RXJS-land.

Note that it returns a BehaviorSubject instance, and will have an initial value of false, so process the return value as needed.

Returns : Subject<any>
isInitializing
isInitializing()
Inherited from BaseComponent
Defined in BaseComponent:95

Main flag to indicate the init status

Returns : boolean
ngOnInit
ngOnInit()
Inherited from BaseComponent
Defined in BaseComponent:50
Returns : void
Async waitForDeps
waitForDeps()
Inherited from BaseComponent
Defined in BaseComponent:78

Wait for dependencies to initialise

Returns : Promise<any>
Async waitForInit
waitForInit()
Inherited from BaseComponent
Defined in BaseComponent:89

For those interested in the init from the Promise-land

Returns : Promise<any>

Properties

allRoles
Type : Role[]
Default value : []
allUsers
Type : User[]
Default value : []
currentUser
Type : User
Default value : null as any
filteredUsers
Type : any[]
Default value : []
hiddenUsers
Type : any
Default value : ['']
isDetailsModalShown
Type : boolean
Default value : false
isNewUserModalShown
Type : boolean
Default value : false
newUserForm
Type : FormGroup
Default value : null as any
newUserMsg
Type : string
Default value : ''
newUserMsgType
Type : string
Default value : 'info'
searchFilter
Type : literal type
Default value : { name: '', prevName: '', users: [ {value: null, label:'Any', checked:true}] }
showToken
Type : boolean
Default value : false
submitted
Type : boolean
Default value : false
title
Type : string
Default value : '@researchdatabox/manage-users'
updateDetailsMsg
Type : string
Default value : ''
updateDetailsMsgType
Type : string
Default value : 'info'
updateUserForm
Type : FormGroup
Default value : null as any
Optional userDetailsModal
Type : ModalDirective
Decorators :
@ViewChild('userDetailsModal', {static: false})
Optional userNewModal
Type : ModalDirective
Decorators :
@ViewChild('userNewModal', {static: false})
Protected brandingAndPortalUrl
Type : string
Default value : ''
Inherited from BaseComponent
Defined in BaseComponent:42
Private filterFn
Default value : function(initStat: boolean) { return initStat; }
Inherited from BaseComponent
Defined in BaseComponent:40
Protected initDependencies
Type : Initable[]
Default value : []
Inherited from BaseComponent
Defined in BaseComponent:39
Protected initSubject
Type : BehaviorSubject<any>
Default value : new BehaviorSubject(false)
Inherited from BaseComponent
Defined in BaseComponent:38
Protected isReady
Type : boolean
Default value : false
Inherited from BaseComponent
Defined in BaseComponent:37
import { Component, Inject, ViewChild } from '@angular/core';
import { ModalDirective } from 'ngx-bootstrap/modal';
import { FormArray, FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Role, User, UserLoginResult, SaveResult } from '@researchdatabox/portal-ng-common';
import { BaseComponent, LoggerService, TranslationService, UserService} from '@researchdatabox/portal-ng-common';
import { UserForm, matchingValuesValidator, optionalEmailValidator, passwordStrengthValidator } from './forms';
import * as _ from 'lodash';

@Component({
  selector: 'manage-users',
  templateUrl: './manage-users.component.html'
})
export class ManageUsersComponent extends BaseComponent {

  title = '@researchdatabox/manage-users';
  
  allUsers: User[] = [];
  filteredUsers: any[] = [];
  allRoles: Role[] = [];

  searchFilter: { name: string, 
                  prevName: string, 
                  users: any[] 
                } = {
                      name: '', 
                      prevName: '', 
                      users: [ {value: null, label:'Any', checked:true}]
                    };

  hiddenUsers: any = [''];
  currentUser: User = null as any;

  updateDetailsMsg: string = '';
  updateDetailsMsgType: string = 'info';
  newUserMsg: string = '';
  newUserMsgType: string = 'info';

  @ViewChild('userDetailsModal', { static: false }) userDetailsModal?: ModalDirective;
  @ViewChild('userNewModal', { static: false }) userNewModal?: ModalDirective;

  isDetailsModalShown: boolean = false;
  isNewUserModalShown: boolean = false;
  updateUserForm: FormGroup = null as any;;
  newUserForm: FormGroup = null as any;;
  submitted: boolean = false;
  showToken: boolean = false;

  constructor(
    @Inject(LoggerService) private loggerService: LoggerService,
    @Inject(TranslationService) private translationService: TranslationService,
    @Inject(UserService) private userService: UserService,
    @Inject(FormBuilder) private _fb: FormBuilder
  ) {
    super();
    this.loggerService.debug(`Manage Users waiting for deps to init...`); 
    this.initDependencies = [this.translationService, this.userService];
  }

  protected override async initComponent():Promise<void> {
    let roles: any = await this.userService.getBrandRoles();
    for(let role of roles) {
      this.allRoles.push(role);
    }
    await this.refreshUsers();
  }

  setupForms(newUser: boolean) {
    this.submitted = false;

    if(newUser) {

      let newRolesControlArray = new FormArray(this.allRoles.map((role) => {
        return new FormGroup({
          key: new FormControl(role.id),
          value: new FormControl(role.name),
          checked: new FormControl(false),
        });
      }));

      const pwGroup_new = this._fb.group(
        {
          password: [''],
          confirmPassword: ['']
        }
      );
      pwGroup_new.setValidators([matchingValuesValidator('password', 'confirmPassword'), passwordStrengthValidator('confirmPassword')]);
      
      this.newUserForm = this._fb.group({
        username: ['', Validators.required],
        name: ['', Validators.required],
        email: ['', optionalEmailValidator],
        passwords: pwGroup_new,
        allRoles: newRolesControlArray,
        roles: [this.mapRoles(newRolesControlArray.value), Validators.required]
      });

      newRolesControlArray.valueChanges.subscribe((v) => {
        this.newUserForm.controls['roles'].setValue(this.mapRoles(v));
      });

    } else {

      let updateRolesControlArray = new FormArray(this.allRoles.map((role) => {
        return new FormGroup({
          key: new FormControl(role.id),
          value: new FormControl(role.name),
          checked: new FormControl(_.includes(_.flatMap(this.currentUser.roles, role => { return role['name']; }), role.name)),
        });
      }));

      const pwGroup_update = this._fb.group(
        {
          password: [''],
          confirmPassword: ['']
        }
      );

      pwGroup_update.setValidators([matchingValuesValidator('password', 'confirmPassword'), passwordStrengthValidator('confirmPassword')]);

      this.updateUserForm = this._fb.group({
        userid: this.currentUser.id,
        username: this.currentUser.username,
        name: [this.currentUser.name, Validators.required],
        email: [this.currentUser.email, optionalEmailValidator],
        passwords: pwGroup_update,
        allRoles: updateRolesControlArray,
        roles: [this.mapRoles(updateRolesControlArray.value), Validators.required]
      });

      updateRolesControlArray.valueChanges.subscribe((v) => {
        this.updateUserForm.controls['roles'].setValue(this.mapRoles(v));
      });
      
    }
  }

  mapRoles(roles: any) {
    let selectedRoles = roles.filter((role: any) => role.checked).map((r: any) => {
      let ret: Role = {      
        id: '',
        name: '',
        users: [],
        hasRole: true
      };
      ret.id = r.key;
      ret.name = r.value;
      return ret;
      });
    return selectedRoles.length ? selectedRoles : null;
  }

  async refreshUsers() {
    let users: any =  await this.userService.getUsers();
    for(let user of users) {
      this.allUsers.push(user);
    }
    _.forEach(this.searchFilter.users, (user:any) => {
      this.searchFilter.users.pop();
    });
    this.filteredUsers = [];
    _.forEach(users, (user:any) => {
      this.searchFilter.users.push({value:user.name, label:user.name, checked:false});
      if (!_.includes(this.hiddenUsers, user.username)) {
        this.filteredUsers.push(user);
      }
    });
    _.map(this.filteredUsers, (user:any)=> {user.roleStr = _.join(_.map(user.roles, 'name'), ', ')});
  }

  editUser(username: string) {
    this.showToken = false;
    this.setUpdateMessage();
    let user = _.find(this.allUsers, (user:any)=>{return user.username == username});
    if(!_.isUndefined(user)) {
      this.currentUser = user;
    }
    this.setupForms(false);
    this.showDetailsModal();
  }

  newUser() {
    this.setNewUserMessage();
    this.setupForms(true);
    this.showNewUserModal();
  }

  showDetailsModal(): void {
    this.isDetailsModalShown = true;
    this.userDetailsModal?.show();
  }

  hideDetailsModal(): void {
    if(!_.isUndefined(this.userDetailsModal)) {
      this.userDetailsModal.hide();
    }
  }

  onDetailsModalHidden(): void {
    this.isDetailsModalShown = false;
  }

  showNewUserModal(): void {
    this.isNewUserModalShown = true;
    
  }

  hideNewUserModal(): void {
    if(!_.isUndefined(this.userNewModal)) {
      this.userNewModal.hide();
    }
  }

  onNewUserHidden(): void {
    this.isNewUserModalShown = false;
  }

  genKey(userid: string) {
    this.setUpdateMessage('Generating...', 'primary');
    this.userService.genKey(userid).then((saveRes:any) => { //SaveResult
      if (saveRes.status) {
        this.showToken = true;
        this.currentUser.token = saveRes.message;
        this.refreshUsers();
        this.setUpdateMessage('Token generated.', 'primary');
      } else {
        this.setUpdateMessage(saveRes.message, 'danger');
      }
    });
  }

  revokeKey(userid: string) {
    this.setUpdateMessage('Revoking...', 'primary');
    this.userService.revokeKey(userid).then((saveRes:any) => { //SaveResult
      if (saveRes.status) {
        this.currentUser.token = '';
        this.refreshUsers();
        this.setUpdateMessage('Token revoked.', 'primary');
      } else {
        this.setUpdateMessage(saveRes.message, 'danger');
      }
    });
  }

  async updateUserSubmit(user: UserForm, isValid: boolean) {
    this.submitted = true;
    if (!isValid){
      this.setUpdateMessage(this.translationService.t('manage-users-validation-submit'), 'danger');
      return;
    }
    let details: { name: string, email: string, password: string, roles: any[] } =
      { name: user.name, email: user.email, password: user.passwords.password, roles: [] };
    _.forEach(user.roles, (role:any) => {
      details.roles.push(role.name);
    });
    this.setUpdateMessage('Saving...', 'primary');

    let saveRes:any = await this.userService.updateUserDetails(user.userid, details); //SaveResult
    if (saveRes.status) {
      this.hideDetailsModal();
      this.refreshUsers();
      this.setUpdateMessage();
    } else {
      this.setUpdateMessage(saveRes.message, 'danger');
    }
  }

  async newUserSubmit(user: UserForm, isValid: boolean) {
    this.submitted = true;
    if (!isValid){
      this.setNewUserMessage(this.translationService.t('manage-users-validation-submit'), 'danger');
      return;
    }
    let details: { name: string, email: string, password: string, roles: any[] } =
      { name: user.name, email: user.email, password: user.passwords.password, roles: [] };

    _.forEach(user.roles, (role:any) => {
      details.roles.push(role.name);
    });

    this.setNewUserMessage('Saving...', 'primary');
    let saveRes:any = await this.userService.addLocalUser(user.username, details); //SaveResult
    if (saveRes.status) {
      this.hideNewUserModal();
      this.refreshUsers();
      this.setNewUserMessage();
    } else {
      this.setNewUserMessage(saveRes.message, 'danger');
    }
  }

  setUpdateMessage(msg:any=undefined, type:string='primary') {
    this.updateDetailsMsg = msg;
    this.updateDetailsMsgType = type;
  }

  setNewUserMessage(msg:any=undefined, type:string='primary') {
    this.newUserMsg = msg;
    this.newUserMsgType = type;
  }

  onFilterChange() {
    if (this.searchFilter.name != this.searchFilter.prevName) {
      this.searchFilter.prevName = this.searchFilter.name;
      var nameFilter =_.isEmpty(this.searchFilter.name) ? '' : _.trim(this.searchFilter.name);

      this.filteredUsers = _.filter(this.allUsers, (user:any) => {
        var hasNameMatch = nameFilter == '' ? true : (_.toLower(user.name).indexOf(_.toLower(this.searchFilter.name)) >= 0);
        return hasNameMatch;
      });
    }
  }

  resetFilter() {
    this.searchFilter.name = '';
    _.map(this.searchFilter.users, (user:any)=> user.checked = user.value == null);
    this.onFilterChange();
  }

  isUpdateUserFormConfirmPasswordTouched() {
    let passControls = (this.updateUserForm.controls['passwords'] as FormGroup).controls;
    if(passControls['confirmPassword'] && passControls['confirmPassword'].touched) {
        return true;  
    }
    return false;
  }
  
  getUpdateUserPasswordErrors() {
    let errors = this.updateUserForm.controls['passwords'].errors;
    let errorMessages = [];
    if(errors) {
      for(let errorMsg of errors['passwordStrengthDetails'].errors) {
        errorMessages.push(errorMsg);
      }
    }

    return errorMessages;
  }

  getNewUserPasswordErrors() {
    let errors = this.newUserForm.controls['passwords'].errors;
    let errorMessages = [];
    if(errors) {
      for(let errorMsg of errors['passwordStrengthDetails'].errors) {
        errorMessages.push(errorMsg);
      }
    }

    return errorMessages;
  }

  getNewUserPasswordFormControls() {
    return (this.newUserForm.controls['passwords'] as FormGroup).controls;
  }

  getUpdateUserFormControls() {
    return (this.updateUserForm.get('allRoles') as FormArray).controls as FormGroup[];
  }

  getNewUserFormControls() {
    return (this.newUserForm.get('allRoles') as FormArray).controls as FormGroup[];
  }

}
<div class="col-md-offset-2 col-md-8" *ngIf="isReady">
    <div class="panel panel-default">
        <div class="panel-heading">
        <span class="panel-title">
            {{ 'manage-users-title' | i18next }}
        </span>
        </div>
        <div class="panel-body" style="overflow:scroll">
        <div class="row">
            <div class="col-sm-9">
            <div class="input-group">
                <span class="input-group-addon" id="name-addon">{{ 'manage-users-filter-name' | i18next }}</span>
                <input type="text" (keyup)="onFilterChange()" [(ngModel)]="searchFilter.name" class="form-control" placeholder="{{ 'manage-users-filter-name-placeholder' | i18next }}" [attr.aria-label]="'manage-users-filter-name' | i18next">
                <span (click)="resetFilter()" class="input-group-btn"><button class="btn btn-primary" type='button'>Reset</button></span>
            </div>
            </div>
            <div class="col-sm-3">
                <span (click)="newUser()"><button class="btn btn-primary" type='button'>{{ 'manage-users-add-local' | i18next }}</button></span>
            </div>
        </div>
        <div>
            <br/>
        </div>
        <div>
            <br/>
        </div>
        <div class="table-responsive">
            <table class="table table-bordered table-striped table-hover">
            <thead>
                <tr>
                <th>{{ 'manage-users-name' | i18next }}</th>
                <th>{{ 'manage-users-email' | i18next }}</th>
                <th>{{ 'manage-users-role' | i18next }}</th>
                <th>{{ 'manage-users-api' | i18next }}</th>
                <th>{{ 'manage-users-action' | i18next }}</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let user of filteredUsers">
                <td>{{user.name}}</td>
                <td>{{user.email}}</td>
                <td>{{user.roleStr}}</td>
                <td align="center">
                    <i class="fa fa-check" aria-hidden="true" *ngIf="user.token"></i>
                </td>
                <td>
                    <a style="cursor:pointer" (click)="editUser(user.username)">Edit</a>
                </td>
                </tr>
            </tbody>
            </table>
        </div>
        </div>
    </div>
</div>
  
<!-- User Details Modal -->
<div *ngIf="isDetailsModalShown" [config]="{backdrop: 'static', show: true}" (onHidden)="onDetailsModalHidden()" bsModal #userDetailsModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="detailsform" >
    <div class="modal-dialog modal-md">
        <!-- Modal content-->
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title">{{ 'manage-users-edit' | i18next }}</h4>
            </div>
            <div class="modal-body">
                <form id="detailsform" [formGroup]="updateUserForm" novalidate (ngSubmit)="updateUserSubmit(updateUserForm.value, updateUserForm.valid)">
                    <div class="table-responsive">
                        <table class="table">
                            <tbody>
                                <tr *ngIf="currentUser.type == 'local'">
                                    <td>{{ 'manage-users-username' | i18next }}</td>
                                    <td>{{ currentUser.username }}</td>
                                </tr>
                                <tr>
                                    <td>{{ 'manage-users-name' | i18next }}</td>
                                    <td *ngIf="currentUser.type == 'local'">
                                        <input type="text" formControlName="name" class="form-control input-sm chat-input"/>
                                        <div class='form-text error text-danger' *ngIf="updateUserForm.controls['name'].touched || submitted">
                                            <div *ngIf="updateUserForm.controls['name'].hasError('required')">{{ 'manage-users-validation-name' | i18next }}</div>
                                        </div>
                                    </td>
                                    <td *ngIf="currentUser.type != 'local'">{{currentUser.name}}</td>
                                </tr>
                                <tr>
                                    <td>{{ 'manage-users-email' | i18next }}</td>
                                    <td *ngIf="currentUser.type == 'local'">
                                        <input type="email" formControlName="email" class="form-control input-sm chat-input"/>
                                        <div class='form-text error text-danger' *ngIf="updateUserForm.controls['email'].touched || submitted">
                                            <div *ngIf="updateUserForm.controls['email'].hasError('invalidEmail')">{{ 'manage-users-validation-email' | i18next }}</div>
                                            </div>
                                    </td>
                                    <td *ngIf="currentUser.type != 'local'">{{currentUser.email}}</td>
                                </tr>
                                <tr>
                                    <td>{{ 'manage-users-password' | i18next }}</td>
                                    <td *ngIf="currentUser.type == 'local'">
                                        <div formGroupName="passwords">
                                            <input type="password" formControlName="password" class="form-control input-sm chat-input" placeholder="{{ 'manage-users-update-password' | i18next }}"/>
                                        </div>
                                    </td>
                                    <td *ngIf="currentUser.type != 'local'">{{ 'manage-users-aaf-password' | i18next}}</td>
                                </tr>
                                <tr *ngIf="currentUser.type == 'local'">
                                    <td>{{ 'manage-users-confirm-password' | i18next }}</td>
                                    <td>
                                        <div formGroupName="passwords">
                                        <input type="password" formControlName="confirmPassword" class="form-control input-sm chat-input" placeholder="Confirm Password"/>
                                        </div>
                                        <div class='form-text error text-danger' *ngIf="isUpdateUserFormConfirmPasswordTouched() || submitted">
                                        <div *ngIf="updateUserForm.controls['passwords'].hasError('mismatched')">{{ 'manage-users-validation-confirmpassword' | i18next }}</div>
                                        <ng-container *ngIf="updateUserForm.controls['passwords'].hasError('passwordStrength')" >
                                            <div *ngFor="let errorMsg of getUpdateUserPasswordErrors()" >
                                            {{ errorMsg | i18next }}
                                            </div>
                                        </ng-container>
                                        </div>
                                    </td>
                                </tr>
                                <tr>
                                    <td>{{ 'manage-users-api' | i18next }}</td>
                                    <td *ngIf="!currentUser.token">
                                        <button type="button" class="btn btn-primary" (click)="genKey(currentUser.id)">{{ 'manage-users-api-generate' | i18next }}</button>
                                    </td>
                                    <td *ngIf="currentUser.token">
                                        <ng-container *ngIf="showToken">
                                        <p>{{ 'manage-users-token-message' | i18next }}</p>
                                        <p><strong>{{ currentUser.token }}</strong></p>
                                        </ng-container>
                                        <button type="button" class="btn btn-primary" (click)="revokeKey(currentUser.id)">{{ 'manage-users-api-revoke' | i18next }}</button>
                                    </td>
                                </tr>
                                <tr>
                                    <td class="col-md-2">{{ 'manage-roles-role' | i18next }}</td>
                                    <td class="col-md-8">
                                        <div [formArrayName]="'allRoles'">
                                            <div *ngFor="let role of getUpdateUserFormControls(); let i = index;" [formGroup]="role">
                                                <input type="checkbox" formControlName="checked" id="role_{{ role.controls['key'].value }}">
                                                <label attr.for="role_{{ role.controls['key'].value }}">{{ role.controls['value'].value }}</label>
                                            </div>
                                            <div class='form-text error text-danger' *ngIf="!updateUserForm.controls['roles'].valid">
                                                <div>{{ 'manage-users-validation-role' | i18next }}</div>
                                            </div>
                                        </div>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </form>
                <div class="bg-{{updateDetailsMsgType}} center-block">{{updateDetailsMsg}}</div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" form="detailsform" type="submit">{{ 'manage-users-save' | i18next }}</button>
                <button type="button" class="btn btn-default" (click)="hideDetailsModal()">{{ 'manage-users-cancel' | i18next }}</button>
            </div>
        </div>
    </div>
</div>
  
<!-- New User Modal -->
<div *ngIf="isNewUserModalShown" [config]="{ show: true }" (onHidden)="onNewUserHidden()" bsModal #userNewModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog">
        <!-- Modal content-->
        <div class="modal-content">
            <div class="modal-header">
                <span class="modal-title h4-header">{{ 'manage-users-new' | i18next }}</span>
            </div>
            <div class="modal-body">
            <form id="newform" [formGroup]="newUserForm" novalidate (ngSubmit)="newUserSubmit(newUserForm.value, newUserForm.valid)">
                <div class="table-responsive">
                    <table class="table">
                    <tbody>
                        <tr>
                            <td>{{ 'manage-users-username' | i18next }}</td>
                            <td>
                                <input type="text" formControlName="username" class="form-control input-sm chat-input" placeholder="{{ 'manage-users-username' | i18next }}" [attr.aria-label]="'manage-users-username' | i18next"/>
                                <div class='form-text error text-danger' *ngIf="newUserForm.controls['username'].touched || submitted">
                                    <div *ngIf="newUserForm.controls['username'].hasError('required')">{{ 'manage-users-validation-username' | i18next }}</div>
                                </div>
                            </td>
                        </tr>
                        <tr>
                        <td>{{ 'manage-users-name' | i18next }}</td>
                        <td>
                            <input type="text" formControlName="name" class="form-control input-sm chat-input" placeholder="{{ 'manage-users-name' | i18next }}" [attr.aria-label]="'manage-users-name' | i18next "/>
                            <div class='form-text error text-danger' *ngIf="newUserForm.controls['name'].touched || submitted">
                                <div *ngIf="newUserForm.controls['name'].hasError('required')">{{ 'manage-users-validation-name' | i18next }}</div>
                                </div>
                        </td>
                        </tr>
                        <tr>
                        <td>{{ 'manage-users-email' | i18next }}</td>
                        <td>
                            <input type="email" formControlName="email" class="form-control input-sm chat-input" placeholder="{{ 'manage-users-email' | i18next }}" [attr.aria-label]="'manage-users-email' | i18next"/>
                            <div class='form-text error text-danger' *ngIf="newUserForm.controls['email'].touched || submitted">
                                <div *ngIf="newUserForm.controls['email'].hasError('invalidEmail')">{{ 'manage-users-validation-email' | i18next }}</div>
                                </div>
                        </td>
                        </tr>
                        <tr>
                        <td>{{ 'manage-users-password' | i18next }}</td>
                        <td>
                            <div formGroupName="passwords">
                                <input type="password" formControlName="password" class="form-control input-sm chat-input" placeholder="{{ 'manage-users-password' | i18next }}" [attr.aria-label]="'manage-users-password' | i18next "/>
                            </div>
                            <div class='form-text error text-danger' *ngIf="getNewUserPasswordFormControls()['password'].touched || submitted">
                                <div *ngIf="getNewUserPasswordFormControls()['password'].hasError('required')">{{ 'manage-users-validation-password' | i18next }}</div>
                                </div>
                        </td>
                        </tr>
                        <tr>
                            <td>{{ 'manage-users-confirm-password' | i18next }}</td>
                            <td>
                                <div formGroupName="passwords">
                                    <input type="password" formControlName="confirmPassword" class="form-control input-sm chat-input" placeholder="{{ 'manage-users-confirm-password' | i18next }}" [attr.aria-label]="'manage-users-confirm-password' | i18next"/>
                                </div>
                                <div class='form-text error text-danger' *ngIf="getNewUserPasswordFormControls()['confirmPassword'].touched || submitted">
                                    <div *ngIf="newUserForm.controls['passwords'].hasError('mismatched')">{{ 'manage-users-validation-confirmpassword' | i18next }}</div>
                                    <ng-container *ngIf="newUserForm.controls['passwords'].hasError('passwordStrength')" >
                                        <div *ngFor="let errorMsg of getNewUserPasswordErrors()" >
                                        {{ errorMsg | i18next }}
                                        </div>
                                    </ng-container>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <td class="col-md-2">{{ 'manage-roles-role' | i18next }}</td>
                            <td class="col-md-8">
                                <div [formArrayName]="'allRoles'">
                                    <div *ngFor="let role of getNewUserFormControls(); let i = index;" [formGroup]="role">
                                        <input type="checkbox" formControlName="checked" id="role_{{ role.controls['key'].value }}">
                                        <label attr.for="role_{{ role.controls['key'].value }}">{{ role.controls['value'].value }}</label>
                                    </div>
                                    <div class='form-text error text-danger' *ngIf="!newUserForm.controls['roles'].valid">
                                        <div>{{ 'manage-users-validation-role' | i18next }}</div>
                                        </div>
                                    </div>
                            </td>
                            </tr>
                    </tbody>
                    </table>
                </div>
                </form>
                <div class="bg-{{newUserMsgType}} center-block">{{ newUserMsg }}</div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" form="newform" type="submit">{{ 'manage-users-save' | i18next }}</button>
                <button type="button" class="btn btn-default" (click)="hideNewUserModal()">{{ 'manage-users-cancel' | i18next }}</button>
            </div>
        </div>
    </div>
</div>
  
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""