File

assets/angular/shared/form/field-repeatable.component.ts

Description

Repeatable Field Container

Author: Shilo Banihit

Extends

Container

Index

Properties
Methods

Constructor

constructor(options: any, injector: any)
Parameters :
Name Type Optional Description
options any
injector any

Methods

addElem
addElem()
Returns : any
createNewElem
createNewElem(baseFieldInst: any, value: any)
Parameters :
Name Type Optional Description
baseFieldInst any
value any
Returns : any
getGroup
getGroup(group: any, fieldMap: any)
Parameters :
Name Type Optional Description
group any
fieldMap any
Returns : void
getInitArrayEntry
getInitArrayEntry()
Returns : {}
removeElem
removeElem(index: number)
Parameters :
Name Type Optional Description
index number
Returns : void
Public triggerValidation
triggerValidation()
Returns : void

Properties

addButtonClass
addButtonClass: any
Type : any
addButtonText
addButtonText: string
Type : string
addButtonTextClass
addButtonTextClass: any
Type : any
forceClone
forceClone: string[]
Type : string[]
removeButtonClass
removeButtonClass: any
Type : any
removeButtonText
removeButtonText: string
Type : string
removeButtonTextClass
removeButtonTextClass: any
Type : any
skipClone
skipClone: string[]
Type : string[]
import { Input, Component, OnInit, Output, EventEmitter} from '@angular/core';
import { SimpleComponent } from './field-simple.component';
import { Container } from './field-simple';
import { FormArray } from '@angular/forms';
import { ContributorComponent, ContributorField } from './field-contributor.component';
import * as _ from "lodash-lib";
import { ChangeDetectorRef } from '@angular/core';

/**
 * Repeatable Field Container
 *
 * Author: <a href='https://github.com/shilob' target='_blank'>Shilo Banihit</a>
 *
 */
export class RepeatableContainer extends Container {
  addButtonText: string;
  removeButtonText: string;
  skipClone: string[];
  forceClone: string[];
  addButtonTextClass: any;
  removeButtonTextClass: any;
  addButtonClass: any;
  removeButtonClass: any;

  constructor(options: any, injector: any) {
    super(options, injector);
    this.hasGroup = true;
    this.addButtonText = options['addButtonText'] || '';
    this.removeButtonText = options['removeButtonText'] || null;
    this.skipClone = options['skipClone'] || [];
    this.forceClone = options['forceClone'] || [];
    this.addButtonTextClass = options['addButtonTextClass'] || 'btn btn-success pull-right';
    this.addButtonClass = options['addButtonClass'] || 'fa fa-plus-circle pull-right btn text-30 btn-success';
    this.removeButtonTextClass = options['removeButtonTextClass'] || 'btn btn-danger pull-left';
    this.removeButtonClass = options['removeButtonClass'] || 'fa fa-minus-circle btn text-20 pull-left btn-danger';

  }

  getInitArrayEntry() {
    return [this.fields[0].createFormModel()];
  }

  getGroup(group: any, fieldMap: any) {
    fieldMap[this.name] = {field:this};
    if (!this.value || this.value.length == 0) {
      this.formModel = new FormArray(this.getInitArrayEntry());
    } else {
      let fieldCtr = 0;
      const baseField = this.fields[0];
      const elems = [];
      this.fields = _.map(this.value, (valueElem:any) => {
        let fieldClone = null;
        if (fieldCtr == 0) {
          fieldClone = baseField;
        } else {
          fieldClone = this.createNewElem(baseField, valueElem);
        }
        fieldCtr++;
        elems.push(fieldClone.createFormModel(valueElem));
        return fieldClone;
      });
      this.formModel = new FormArray(elems);
      _.each(this.fields, f => {
        f.setupEventHandlers();
      });
    }
    fieldMap[this.name].control = this.formModel;
    if (this.groupName) {
      if (group[this.groupName]) {
        group[this.groupName].addControl(this.name, this.formModel);
      } else {
        const fg = {};
        fg[this.name] = this.formModel;
        group[this.groupName] = fg;
      }
    } else {
      group[this.name] = this.formModel;
    }
  }

  createNewElem(baseFieldInst: any, value:any = null) {
    const newOpts = _.cloneDeep(baseFieldInst.options);
    newOpts.value = null;
    const newInst = new baseFieldInst.constructor(newOpts, this.injector);
    _.forEach(this.skipClone, (f: any)=> {
      newInst[f] = null;
    });
    _.forEach(this.forceClone, (f: any) => {
      newInst[f] = _.cloneDeep(baseFieldInst[f]);
    });
    if (_.isFunction(newInst.postInit)) {
      newInst.postInit(value);
    }
    return newInst;
  }

  addElem() {
    const newElem = this.createNewElem(this.fields[0]);
    if (_.isFunction(newElem.setEmptyValue)) {
      newElem.setEmptyValue();
    }
    this.fields.push(newElem);
    const newFormModel = newElem.createFormModel();
    this.formModel.push(newFormModel);
    return newElem;
  }

  removeElem(index: number) {
    _.remove(this.fields, (val:any, idx: number) => { return idx == index });
    this.formModel.removeAt(index);
  }

  public triggerValidation() {
    _.forEach(this.fields, (f:any) => {
      f.triggerValidation();
    });
  }
}

export class EmbeddableComponent extends SimpleComponent {
  @Input() isEmbedded: boolean = false;
  @Input() canRemove: boolean = false;
  @Input() removeBtnText: string = null;
  @Input() removeBtnClass: string = 'btn fa fa-minus-circle btn text-20 pull-left btn btn-danger';
  @Input() index: number;
  @Output() onRemoveBtnClick: EventEmitter<any> = new EventEmitter<any>();

  onRemove(event: any) {
    this.onRemoveBtnClick.emit([event, this.index]);
  }

  public getGroupClass(fldName:string=null): string {
    let baseClass = 'form-group';
    if (this.isEmbedded) {
      baseClass = '';
    }
    return `${baseClass} ${this.hasRequiredError() ? 'has-error' : '' }`;
  }
}

export class RepeatableComponent extends SimpleComponent {
  field: RepeatableContainer;

  addElem(event: any) {
    this.field.addElem();
  }

  removeElem(event: any, i: number) {
    this.field.removeElem(i);
  }
}

@Component({
  selector: 'repeatable-vocab',
  template: `
  <div *ngIf="field.editMode">
    <div class="row">
      <div class="col-md-12">
      <label>{{field.label}}
        <button type="button" class="btn btn-default" *ngIf="field.help" (click)="toggleHelp()"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span></button>
      </label>
      <span id="{{ 'helpBlock_' + field.name }}" class="help-block" *ngIf="this.helpShow" [innerHtml]="field.help"></span>
      </div>
    </div>
    <div *ngFor="let fieldElem of field.fields; let i = index;" class="row">
      <span class="col-xs-12">
        <rb-vocab [field]="fieldElem" [form]="form" [fieldMap]="fieldMap" [isEmbedded]="true" [removeBtnText]="field.removeButtonText" [removeBtnClass]="field.removeButtonClass" [canRemove]="field.fields.length > 1" (onRemoveBtnClick)="removeElem($event[0], $event[1])" [index]="i"></rb-vocab>
      </span>
    </div>
    <div class="row">
      <span class="col-xs-12">
        <button *ngIf="field.addButtonText" type='button' (click)="addElem($event)" [ngClass]="field.addButtonTextClass" >{{field.addButtonText}}</button>
        <button *ngIf="!field.addButtonText" type='button' (click)="addElem($event)" [ngClass]="field.addButtonClass"></button>
      </span>
    </div>
  </div>
  <li *ngIf="!field.editMode" class="key-value-pair">
    <span *ngIf="field.label" class="key">{{field.label}}</span>
    <span class="value">
      <ul class="key-value-list">
        <rb-vocab *ngFor="let fieldElem of field.fields; let i = index;" [field]="fieldElem" [form]="form" [fieldMap]="fieldMap"></rb-vocab>
      </ul>
    </span>
  </li>
  `,
})
export class RepeatableVocabComponent extends RepeatableComponent {
}

export class RepeatableContributor extends RepeatableContainer {
  fields: ContributorField[];
}

@Component({
  selector: 'repeatable-contributor',
  template: `
  <div *ngIf="field.editMode">
    <div *ngFor="let fieldElem of field.fields; let i = index;" class="row">
      <span class="col-xs-10">
        <rb-contributor [field]="fieldElem" [form]="form" [fieldMap]="fieldMap" [isEmbedded]="true"></rb-contributor>
      </span>
      <span class="col-xs-2">
        <button type='button' *ngIf="field.fields.length > 1 && field.removeButtonText" (click)="removeElem($event, i)"  [ngClass]="field.removeButtonTextClass" [ngStyle]="{'margin-top': fieldElem.marginTop}" >{{field.removeButtonText}}</button>
        <button type='button' *ngIf="field.fields.length > 1 && !field.removeButtonText" (click)="removeElem($event, i)" [ngClass]="field.removeButtonClass" [ngStyle]="{'margin-top': fieldElem.marginTop}" ></button>
      </span>
    </div>
    <div class="row">
      <span class="col-xs-12">
        <button *ngIf="field.addButtonText" type='button' (click)="addElem($event)" [ngClass]="field.addButtonTextClass" >{{field.addButtonText}}</button>
        <button *ngIf="!field.addButtonText" type='button' (click)="addElem($event)" [ngClass]="field.addButtonClass" ></button>
      </span>
    </div>
  </div>
  <div  *ngIf="!field.editMode" class="table-responsive">
    <table class="table table-striped table-condensed">
      <thead><th>{{field.fields[0].nameColHdr}}</th><th>{{field.fields[0].emailColHdr}}</th><th>{{field.fields[0].roleColHdr}}</th></thead>
      <tbody>
        <tr *ngFor="let fieldElem of field.fields; let i = index;">
          <td>{{fieldElem.value.name}}</td>
          <td>{{fieldElem.value.email}}</td>
          <td>{{fieldElem.value.role}}</td>
        </tr>
      </tbody>
    </table>
  </div>
  `,
})
export class RepeatableContributorComponent extends RepeatableComponent implements OnInit {
  field: RepeatableContributor;

  ngOnInit() {
    this.field.fields[0].marginTop = '25px';
  }

  addElem(event: any) {
    const newElem = this.field.addElem();
    newElem.marginTop = '0px';
    newElem.vocabField.initialValue = null;
    newElem.setupEventHandlers();
  }

  removeElem(event: any, i: number) {
    this.field.removeElem(i);
    if (i == 0) {
      this.field.fields[0].marginTop = '25px';
      this.field.fields[0].showHeader = true;
    }
  }
}

results matching ""

    No results matching ""