Skip to content

Instantly share code, notes, and snippets.

@Bidthedog
Created August 2, 2017 15:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Bidthedog/1dc7d10cda1759061c09f44f7b48cbf3 to your computer and use it in GitHub Desktop.
Save Bidthedog/1dc7d10cda1759061c09f44f7b48cbf3 to your computer and use it in GitHub Desktop.
import { Component } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { FormGroup } from '@angular/forms';
import { FormServiceBaseService } from './form-service-base.service';
import { HttpServiceBaseService } from '../shared/http-helpers/http-service-base.service';
import { Debug } from '../shared/debug';
import { IEntityBase } from '../model/ientity-base';
@Component({})
export abstract class FormComponentBaseComponent<TDataModel extends IEntityBase,
TDataService extends HttpServiceBaseService<TDataModel>,
TFormService extends FormServiceBaseService<TDataModel, TDataService>> {
/**
* Override to set this component's sub FormGroup name (i.e. if you want to access { details: {} }, then this should be 'details'
*/
protected abstract readonly formGroupName: string;
constructor(
public formService: TFormService,
protected route: ActivatedRoute
) { }
/**
* Convenience method. Retrieves the component's sub FormGroup name
*/
protected getGroupName(): string {
return this.formGroupName;
}
/**
* Convenience method. Retrieves the component's sub FormGoup
*/
protected getGroup(): FormGroup {
return this.formService.getFormGroup(this.formGroupName);
}
/**
* Convenience method. Retrieves the form service.
*/
protected getFormService(): TFormService {
return this.formService;
}
}
import { OnInit, Input, Component, ElementRef } from '@angular/core';
import { FormGroup, AbstractControl } from '@angular/forms';
import { FormServiceBaseService } from './form-service-base.service';
@Component({})
export class FormControlBaseComponent implements OnInit {
private _group: FormGroup;
private type: string;
@Input() service: FormServiceBaseService<any, any>;
@Input() groupName: string;
@Input() name: string;
// The below properties are overriden if this.service is specified
@Input() friendlyName: string;
@Input() helpText: string;
@Input() required: boolean;
@Input() set group(group: FormGroup) { this._group = group; };
get group() {
// Lazy load the group from the service, if not set manually
if (!this._group) {
if (!this.service || !this.groupName) {
// No service resolution available, user must specify service or group binding
throw new Error(`'group' property is required by '${this.type}' component '${this.name}'`);
}
// Resolve properties using service and formGroupName
// Override control defaults with config data
this._group = this.service.getFormGroup(this.groupName);
}
return this._group;
}
constructor(
protected element: ElementRef
) { }
ngOnInit() {
this.type = this.element.nativeElement.tagName.toLowerCase();
if (!this.name) {
throw new Error(`'name' property is required by '${this.type}' component. Specify manually in the template.`);
}
this.setupFromConfig();
if (!this.friendlyName) {
throw new Error(`'friendlyName' property is required by '${this.type}' component '${this.name}'`);
}
}
protected setupFromConfig() {
if (!this.service || !this.groupName) {
// Nothing to set up
return;
}
this.helpText = this.service.getFieldProperty(this.groupName, this.name, 'helpText');
this.friendlyName = this.service.getFieldProperty(this.groupName, this.name, 'friendlyName');
// Set up generic validator aesthetics / HTML5 properties
const validators = this.service.getFieldProperty(this.groupName, this.name, 'validators');
if (validators) {
this.required = validators.required;
}
this.setupValidators(validators);
}
/**
* Override this method to setup custom validators for a control component. 'Required' is set up for all components.
* @param validators
*/
protected setupValidators(validators: any) { };
protected get control(): AbstractControl {
return this.group.get(this.name);
}
protected hasError(): boolean {
return !this.control.valid && this.edited();
}
protected hasSuccess(): boolean {
return this.control.valid && this.edited();
}
protected edited(): boolean {
return this.control.dirty;
}
/**
* Retrieves the value of the 'data' property for the specified validatorName configured for this control
* @param propertyName
*/
protected getValidatorData(validatorName: string): any {
const validators = this.service.getFieldProperty(this.groupName, this.name, 'validators');
if (!validators) {
return null;
}
if (validators[validatorName]) {
const data = validators[validatorName].data;
if (!data) {
throw new Error(`Unable to find 'data' property for '${validatorName}' validator required by '${this.type}' component '${this.name}'. Data property must contain the setter value.`);
}
return data;
}
return null;
}
}
import { Validators } from '@angular/forms';
import { Constants } from '../../../app.constants';
import {
FormHelpers,
FormGroupDefinition as gDef,
FormFieldDefinition as fDef,
FormFieldValidator as val
} from '../../../shared-forms/form-helpers/form-helpers';
export class PatientFormDefinition {
public details = new gDef('General', 'details', 10, {
NHSNumber: new fDef(null, 'NHS Number', 'NHSNumber', FormHelpers.getTextValue, 'Must be in the format \'NNN-NNN-NNNN\'', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required'),
pattern: new val(Validators.pattern, '\'{{friendlyName}}\' must be in the format \'NNN-NNN-NNNN\' where N is a digit', Constants.NHSNUMBER_PATTERN)
}),
TitleId: new fDef(null, 'Title', 'TitleId', FormHelpers.getTextValue, 'Please select the patient\'s title', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
FirstName: new fDef(null, 'First Name', 'FirstName', FormHelpers.getTextValue, 'Please enter the patient\'s first name', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
MiddleNames: new fDef(null, 'Middle Name(s)', 'MiddleNames', FormHelpers.getTextValue, 'If the patient has one or more middle names, please enter them here'),
LastName: new fDef(null, 'Last Name', 'LastName', FormHelpers.getTextValue, 'Please enter the patient\'s last name', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
DOB: new fDef(null, 'Date of Birth', 'DOB', FormHelpers.getDateValue, 'Please enter or select the patient\'s Date of Birth', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
GenderId: new fDef(null, 'Gender', 'GenderId', FormHelpers.getLookupValue, 'Please select the patient\'s gender', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
RegionId: new fDef(null, 'Region', 'RegionId', FormHelpers.getLookupValue, 'Please select the geographical region where the patient is being treated - this will be used for determining medical data such as GP and Hospital, and for social grouping and scheduling', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
MaritalStatusId: new fDef(null, 'Marital Status', 'MaritalStatusId', FormHelpers.getLookupValue, 'Please select the patient\'s marital status', {
required: new val(Validators.required, '\'{{friendlyName}}\' is required')
}),
OccupationTypeId: new fDef(null, 'Occupation Status', 'OccupationTypeId', FormHelpers.getLookupValue, 'Please select the closest match for the patient\'s occupation status'),
OccupationId: new fDef(null, 'Occupation', 'OccupationId', FormHelpers.getLookupValue, 'Please select the closest match for the patient\'s occupation'),
LivesWith: new fDef(null, 'Lives With', 'LivesWith', FormHelpers.getTextValue, 'Please detail who the patient lives with currently'),
NextOfKinId: new fDef(null, 'Next of Kin', 'NextOfKinId', FormHelpers.getLookupValue, 'Please add a patient\'s next of kin'),
VehicleLicenseTypeId: new fDef(null, 'Vehicle Licenses', 'VehicleLicenseTypeId', FormHelpers.getMultiLookupValue, 'Please select the types of vehicle license that the patient holds', null, true)
});
public contact = new gDef('Contact', 'contact', 20, {
TelephoneNo: new fDef(null, 'Telephone No.', 'TelephoneNo', FormHelpers.getTextValue, 'Please enter the patient\'s telephone number'),
MobileNo: new fDef(null, 'Mobile No.', 'MobileNo', FormHelpers.getTextValue, 'Please enter the patient\'s mobile number'),
HouseNumber: new fDef(null, 'House Name / Number', 'HouseNumber', FormHelpers.getTextValue, 'Please enter the patient\'s house name or number'),
StreetName: new fDef(null, 'Street Name', 'StreetName', FormHelpers.getTextValue, 'Please enter the patient\'s street name'),
Town: new fDef(null, 'Town', 'Town', FormHelpers.getTextValue, 'Please enter the patient\'s town'),
City: new fDef(null, 'City', 'City', FormHelpers.getTextValue, 'Please enter the patient\'s city'),
County: new fDef(null, 'County', 'County', FormHelpers.getTextValue, 'Please enter the patient\'s county'),
CountryId: new fDef(null, 'Country', 'CountryId', FormHelpers.getLookupValue, 'Please select the patient\'s county'),
Postcode: new fDef(null, 'Postcode', 'Postcode', FormHelpers.getTextValue, 'Please enter the patient\'s postcode', {
pattern: new val(Validators.pattern, '\'{{friendlyName}}\' must be a valid UK postcode', Constants.POSTCODE_PATTERN),
maxLength: new val(Validators.maxLength, '\'{{friendlyName}}\' should be no longer than {{data}} characters', 8)
}),
EmailAddress: new fDef(null, 'Email Address', 'EmailAddress', FormHelpers.getTextValue, 'Please enter the patient\'s email address', {
pattern: new val(Validators.pattern, '\'{{friendlyName}}\' must be a valid email address', Constants.EMAIL_PATTERN),
maxLength: new val(Validators.maxLength, '\'{{friendlyName}}\' should be no longer than {{data}} characters', 300)
}),
});
public medical = new gDef('Medical', 'medical', 30, {
GPId: new fDef(null, 'GP', 'GPId', FormHelpers.getLookupValue, 'Please select a GP - a region must be selected first', {
required: { validator: Validators.required, message: '\'{{friendlyName}}\' is required' }
}),
HospitalId: new fDef(null, 'Hospital', 'admission.HospitalId', FormHelpers.getLookupValue, 'Please select a hospital - a region must be selected first. This field ', {
required: { validator: Validators.required, message: '\'{{friendlyName}}\' is required' }
}, false, false),
HospitalNumber: new fDef(null, 'Patient Hospital Number', 'admission.HospitalNumber', FormHelpers.getTextValue, 'Please enter the patient\'s hospital number', {
required: { validator: Validators.required, message: '\'{{friendlyName}}\' is required' }
}),
WardId: new fDef(null, 'Ward', 'admission.WardId', FormHelpers.getLookupValue, 'Please select a ward', {
required: { validator: Validators.required, message: '\'{{friendlyName}}\' is required' }
}),
ConsultantId: new fDef(null, 'Consultant', 'admission.ConsultantId', FormHelpers.getLookupValue, 'Please select a consultant', {
required: { validator: Validators.required, message: '\'{{friendlyName}}\' is required' }
})
});
public conditions = new gDef('Medical Conditions', 'conditions', 40, {
MedicalConditionId: new fDef(null, 'Medical Conditions', 'admission.MedicalConditionId', FormHelpers.getMultiLookupValue, 'Please select the medical conditions that the patient is being treated for during this admission', null, true),
MedicalConditionClassId: new fDef(null, 'Medical Conditions', 'admission.MedicalConditionClassId', FormHelpers.getMultiLookupValue, 'Please specify the classifications for the selected medical conditions', null, true),
});
public risk = new gDef('Risk Factors', 'risk', 50, null);
public diagnosis = new gDef('Diagnosis', 'diagnosis', 60, null);
public treatment = new gDef('Treatment', 'treatment', 70, null);
}
import { FormGroup, FormControl, FormArray } from '@angular/forms';
import { Debug } from '../../shared/debug';
export class FormGroupDefinition {
constructor(
public friendlyName: string,
public urlSegment: string,
public order: number,
public fields: any
) { }
}
export class FormFieldDefinition<T> {
constructor(
public defaultValue: T,
public friendlyName: string,
public modelPath: string,
public mappingFunc: (val: T, defaultVal: T) => T,
public helpText: string = null,
public validators: any = null,
public multiValue: boolean = false,
public enabled: boolean = true
) { }
}
export class FormGroupErrors {
constructor(
public group?: string,
public errors?: string[]
) {
this.errors = [] as string[];
}
}
export class FormFieldValidator {
constructor(
public validator: any,
public message: string,
public data: any = null
) { }
}
export class FormHelpers {
/**
* Flattens the passed formValues into the model provided, using the formConfig's modelPath property
* @param model The model to update
* @param formValues The form to use as the data source
* @param formConfig The form config object to use for mapping
*/
public static buildDataModel<TModel>(model: TModel, formValues: FormGroup, formConfig: any): TModel {
if (!model) {
throw new Error(`Unable to build data model - model must be instantiated by the caller`);
}
for (const groupName in formConfig) {
if (!formConfig.hasOwnProperty(groupName)) {
continue;
}
const cfgGroup = this.getConfigGroup(formConfig, groupName);
const valueGroup = formValues.get(groupName) as FormGroup; // Form group
for (const fieldName in cfgGroup.fields) {
if (!cfgGroup.hasOwnProperty(fieldName)) {
continue;
}
const valueField = valueGroup.get(fieldName); // Form value
const modelPath = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'modelPath');
model[modelPath] = valueField.value;
}
}
return model;
}
/**
* Marks all invalid controls as dirty so they can be visually validated
* @param formRoot
*/
public static markInvalidAsDirty(formRoot: FormGroup) {
for (const groupName in formRoot.controls) {
if (!formRoot.controls.hasOwnProperty(groupName)) {
continue;
}
const group = formRoot.get(groupName) as FormGroup;
for (const fieldName in group.controls) {
if (!group.controls.hasOwnProperty(fieldName)) {
continue;
}
const field = group.get(fieldName);
if (!field.valid) {
field.markAsDirty();
}
}
}
}
/**
* Builds a FormGroup from the formConfig passed in. Generally used to create a form model from scrach on initialisation
* @param formConfig
*/
public static buildFormGroup(formConfig: any) {
const groups: any = {};
for (const groupName in formConfig) {
if (!formConfig.hasOwnProperty(groupName)) {
Debug.warn(`Cannot find group '${groupName}' in form config:\r\n${JSON.stringify(formConfig)}`);
continue;
}
const cfgGroup = this.getConfigGroup(formConfig, groupName).fields;
const fields: any = {};
for (const fieldName in cfgGroup) {
if (!cfgGroup.hasOwnProperty(fieldName)) {
Debug.warn(`Cannot find field '${fieldName}' in group '${groupName}' in form config:\r\n${JSON.stringify(formConfig, null, ' ')}`);
continue;
}
const cfgDefaultValue = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'defaultValue');
const cfgValidators = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'validators');
const cfgMultiValue = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'multiValue');
let validators: any = null;
if (cfgValidators) {
validators = this.buildValidators(cfgValidators);
}
// Create the field
fields[fieldName] = new FormControl(cfgDefaultValue, validators);
}
groups[groupName] = new FormGroup(fields);
}
return new FormGroup(groups);
}
/**
* Builds an array of validators with validator functions and data applied from the form configuration
* @param cfgValidators
*/
private static buildValidators(cfgValidators: any) {
const validators: any = [];
for (const validatorName in cfgValidators) {
if (!cfgValidators.hasOwnProperty(validatorName)) {
continue;
}
const vFunc = cfgValidators[validatorName].validator;
const vFuncData = cfgValidators[validatorName].data;
// Create the function with the specified data passed in, if the data field exists
const validatorFunction = vFuncData ? vFunc(vFuncData) : vFunc;
validators.push(validatorFunction);
}
return validators;
}
/**
* Builds an object from the formConfig and populates it with the specified model values, running each field's mapping function. Generally used with formModel.setValue(), formModel.patchValue() or formModel.reset()
* @param formConfig
* @param model
*/
public static buildFormValues(formConfig: any, model: any) {
const groups: any = {};
for (const groupName in formConfig) {
if (!formConfig.hasOwnProperty(groupName)) {
continue;
}
const cfgGroup = this.getConfigGroup(formConfig, groupName).fields;
const fields: any = {};
for (const fieldName in cfgGroup) {
if (!cfgGroup.hasOwnProperty(fieldName)) {
continue;
}
const modelPath = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'modelPath');
const mappingFunc = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'mappingFunc');
const modelValue = model[modelPath];
fields[fieldName] = mappingFunc(modelValue);
}
groups[groupName] = fields;
}
return groups;
}
/**
* Retrieves a list of errors from the specified formRoot, and searches the formConfig for error messages
* @param formConfig
* @param formRoot
*/
public static getFormErrorList(formConfig: any, formRoot: FormGroup): FormGroupErrors[] {
const errors: FormGroupErrors[] = [];
// Search the form for errors
for (const groupName in formRoot.controls) {
if (!formRoot.controls.hasOwnProperty(groupName)) {
continue;
}
const group = formRoot.get(groupName) as FormGroup;
const friendlyGroupName: string = this.getConfigGroup(formConfig, groupName).friendlyName;
const errorGroup = new FormGroupErrors(friendlyGroupName);
for (const fieldName in group.controls) {
if (!group.controls.hasOwnProperty(fieldName)) {
continue;
}
const field = group.get(fieldName);
const friendlyName = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'friendlyName');
for (const errorType in field.errors) {
if (!field.errors.hasOwnProperty(errorType)) {
continue;
}
// Retrieve error message from config
const cfgValidators = this.getConfigFieldProperty(formConfig, groupName, fieldName, 'validators');
if (!cfgValidators) {
Debug.warn(`Unable to find \'validators\' property in form config for \'${fieldName}\' field (case sensitive)`);
continue;
}
const validator = cfgValidators[errorType];
if (!validator) {
Debug.warn(`Unable to find \'${errorType}\' validator in form config for \'${fieldName}\' field (case sensitive)`);
continue;
}
// Do replacements in error message (DRY!)
let formattedMsg = validator.message.replace('{{data}}', validator.data);
formattedMsg = formattedMsg.replace('{{friendlyName}}', friendlyName);
errorGroup.errors.push(formattedMsg);
}
}
if (errorGroup.errors && errorGroup.errors.length > 0) {
errors.push(errorGroup);
}
}
return errors;
}
/*++Mapping Methods */
public static getTextValue(val: string, defaultValue: string = null): string {
return val || defaultValue;
}
public static getDateValue(val: Date, defaultValue: Date = null): Date {
return val || defaultValue;
}
public static getLookupValue(val: number): number {
if (val === undefined || val == null || val <= 0) {
return null;
}
return val;
}
public static getMultiLookupValue(val: number[]): number[] {
if (val === undefined || val == null) {
return null;
}
return val;
}
/*--Mapping Methods */
/*++Config Methods */
public static getConfigGroup(formConfig: any, groupName: string): FormGroupDefinition {
const cfgGroup = formConfig[groupName];
return cfgGroup;
}
public static getConfigGroups(formConfig: any): FormGroupDefinition[] {
const cfgGroups: FormGroupDefinition[] = [];
for (const groupName in formConfig) {
if (!formConfig.hasOwnProperty(groupName)) {
continue;
}
cfgGroups.push(this.getConfigGroup(formConfig, groupName));
}
return cfgGroups;
}
public static getConfigField(formConfig: any, groupName: string, fieldName: string): any {
const cfgGroup = this.getConfigGroup(formConfig, groupName);
if (!cfgGroup) {
return null;
}
const cfgField = cfgGroup.fields[fieldName];
if (!cfgField) {
return null;
}
return cfgField;
}
public static getConfigFieldProperty(formConfig: any, groupName: string, fieldName: string, propertyName: string) {
const cfgField = this.getConfigField(formConfig, groupName, fieldName);
if (!cfgField) {
Debug.warn(`Could not find field '${groupName}.fields.${fieldName}' in form config`);
return null;
}
const cfgProperty = cfgField[propertyName];
if (!cfgProperty) {
return null;
}
return cfgProperty;
}
/*--Config Methods */
}
import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/Rx';
import { IEntityBase } from '../model/ientity-base';
import { FormHelpers, FormGroupErrors } from '../shared-forms/form-helpers/form-helpers';
import { HttpServiceBaseService, HTTPMappedResponse } from '../shared/http-helpers/http-service-base.service';
import { Debug } from '../shared/debug';
@Injectable()
export abstract class FormServiceBaseService<TDataModel extends IEntityBase, TDataService extends HttpServiceBaseService<TDataModel>>{
// ++ Private / Protected fields
private _formModel: FormGroup;
private _dataLoaded: boolean = false;
protected _dataLoadError: boolean = false;
private _formPopulated: boolean = false;
private _formConfig: any;
protected _dataModel: TDataModel;
private _dataModelObserver: Observable<TDataModel> = Observable.create(o => {
o.next(this.createDataModel());
o.complete();
});
protected _submitAttempt: boolean = false;
protected _submitSuccess: boolean = false;
// -- Private fields
// ++ Public getters
public get formModel(): FormGroup { return this._formModel; };
public get dataLoaded(): boolean { return this._dataLoaded; };
public get dataLoadError(): boolean { return this._dataLoadError; };
public get dataModel(): TDataModel { return this._dataModel; };
public get formConfig(): any { return this._formConfig; };
public get formPopulated(): boolean { return this._formPopulated; };
public get submitAttempt(): boolean { return this._submitAttempt; };
public get submitSuccess(): boolean { return this._submitSuccess; };
public get dataModelObserver(): Observable<TDataModel> { return this._dataModelObserver; }
// -- Public getters
constructor(
protected httpDataService: HttpServiceBaseService<TDataModel>
) {
// Set config from overriden method
this._formConfig = this.createConfig();
// Create the form structure immediately
this.createForm();
}
// ++ Abstract members
/**
* Implement onSubmit() to deal with the form submission. Only called once the form is complete and valid.
*/
public onSubmit(): Observable<TDataModel> {
this._submitAttempt = true; // setting true will enable the error summary
if (!this.isValid()) {
// If the form is not valid, mark all invalid fields as dirty
// so they can be visually validated
FormHelpers.markInvalidAsDirty(this.formModel);
return Observable.empty();
}
// Convert form to model
this._dataModel = FormHelpers.buildDataModel(this.createDataModel(), this.formModel, this.formConfig);
// Save model
let observable: Observable<TDataModel>;
if (this.dataModel.Id > 0) {
// Put existing
observable = this
.httpDataService
.put(this.dataModel)
.map(x => x.data);
} else {
// Post new
observable = this
.httpDataService
.post(this.dataModel)
.map(x => x.data);
}
observable
.subscribe(dataModel => {
this._submitSuccess = true;
}, error => {
this._submitSuccess = false;
});
return observable;
}
/**
* Implement createConfig() to return the service's form configuration object.
*/
protected abstract createConfig(): any;
/**
* Retrieves a model then populates the form, returning an observable that can be subscribed to
*/
public subscribeToModel(id: number): Observable<TDataModel> {
// Perform a full service reset so loaders etc show
this.resetForm();
if (id && id > 0) {
// Get data from service
this._dataModelObserver = this.httpDataService.get(id, null).map(x => x.data);
} else {
// Create new model and assign to new observable
this._dataModelObserver = Observable.create(o => {
o.next(this.createDataModel());
o.complete();
});
}
// Subscribe to populate the form on success
this._dataModelObserver
.subscribe(model => this.populateForm(model), e => null);
return this._dataModelObserver;
}
/**
* Override to provide a generics helper - simply new up a TDataModel
*/
protected abstract createDataModel(): TDataModel;
// -- Abstract members
// ++ Public members
public getErrorHTML(): string {
let errorMessage: string = '<p>At least one form error occurred during validation:</p>';
const errors = this.getFormErrorList();
for (const errorGroup of errors) {
errorMessage += `<p>${errorGroup.group}</p><ul>`;
for (const error of errorGroup.errors) {
errorMessage += '<li>' + error + '</li>';
}
errorMessage += '</ul>';
}
return errorMessage;
}
/**
* Returns a list of FormError objects, which contains a list of friendly group names,
* each with a list of human readible errors that have occurred
*/
public getFormErrorList(): FormGroupErrors[] {
return FormHelpers.getFormErrorList(this.formConfig, this.formModel);
}
/**
* Returns true if the form has been populated, is not valid, and has been edited (dirty)
*/
public showErrors(): boolean {
return this.formPopulated && !this.formModel.valid && this.formModel.dirty;
}
/**
* Returns true if the form has been edited (dirty)
*/
public canClickSubmit(): boolean {
return this.formModel.dirty;
}
/**
* Returns true if the form is valid.
*/
public isValid(): boolean {
return this.formModel.valid;
}
public getFieldProperty(groupName: string, fieldName: string, propertyName: string): any {
return FormHelpers.getConfigFieldProperty(this.formConfig, groupName, fieldName, propertyName);
}
public getFormGroup(groupName: string): FormGroup {
return this.formModel.get(groupName) as FormGroup;
}
// -- Public members
// ++ Helpers
private resetForm() {
this._dataLoaded = false;
this._dataLoadError = false;
this._formPopulated = false;
this._dataModel = null;
this._submitAttempt = false;
this._submitSuccess = false;
}
/**
* Called from within the base class constructor. Creates the form and sets the FormModel field.
*/
private createForm(): void {
this._formModel = FormHelpers.buildFormGroup(this.formConfig);
}
/**
* Call once from within getModel to populate the form once data has been loaded
*/
protected populateForm(model: TDataModel): void {
// Set the model
this._dataModel = model;
if (model) {
// Populate the form values
const values = FormHelpers.buildFormValues(this.formConfig, model);
this.formModel.reset(values);
this._dataLoaded = true;
} else {
Debug.warn('dataModel not set for ' + this.constructor.name + '. Unable to populate form model (case sensitive).');
}
this._formPopulated = true;
}
// -- Helpers
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment