Created
August 31, 2022 00:27
-
-
Save harveytoro/4ee2abe61ea52afd43db246f84b96017 to your computer and use it in GitHub Desktop.
Basic Execution: tsc technical-challenge.ts; node technical-challenge.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// API | |
class Form { | |
public identifier: string; | |
public fields: Field<FieldValue>[] = []; | |
constructor(){ | |
// basic identifier implementation for POC | |
this.identifier = Math.random().toString(16).substring(2) | |
} | |
// Adds a new field to the form | |
public addField(field: Field<FieldValue>): void { | |
this.fields.push(field); | |
} | |
// Removes a field from the form | |
public removeField(field: Field<FieldValue>): void { | |
for(let i = 0; i < this.fields.length; i++){ | |
if(this.fields[i].identifier == field.identifier){ | |
this.fields.splice(i, 1); | |
break; | |
} | |
} | |
} | |
// Validates form by calling validation on each field | |
public validate(): Field<FieldValue>[] { | |
var errorFields: Field<FieldValue>[] = []; | |
for(var field of this.fields){ | |
if(!field.validateField()){ | |
errorFields.push(field) | |
} | |
} | |
return errorFields; | |
} | |
// Stub submit that just validates form | |
public submit(): boolean { | |
return this.validate().length == 0; | |
} | |
} | |
class FieldValue {} | |
abstract class Field<ValueType extends FieldValue> { | |
public identifier: string; | |
public label: String; | |
public value: ValueType; | |
public isRequired: Boolean; | |
public defaultValue: ValueType; | |
public isVisible: Boolean; | |
protected notifyOfValueChangeFields: Field<FieldValue>[] = []; | |
protected conditions: {} = {} | |
constructor(label: string, visible: boolean = true){ | |
this.identifier = Math.random().toString(16).substring(2) | |
this.label = label | |
this.isVisible = visible | |
} | |
// Updates the value of the field and notifies intereted fields | |
public updateValue(value: ValueType): void { | |
this.value = value; | |
for(var toNotify of this.notifyOfValueChangeFields){ | |
toNotify.valueUpdated(this); | |
} | |
} | |
// Registeres a fields interest in being notified of value change | |
public notifyOnChange(field: Field<FieldValue>): void { | |
this.notifyOfValueChangeFields.push(field); | |
} | |
// Tells field that a conditional value has been updated | |
public valueUpdated(field: Field<FieldValue>): void { | |
if(!(field.identifier in this.conditions)){ | |
return; | |
} | |
if(field.value == this.conditions[field.identifier]){ | |
this.isVisible = true | |
} | |
} | |
// adds a conditional value to the field | |
public addConditional(field: Field<FieldValue>, value: FieldValue): void { | |
field.notifyOnChange(this); | |
this.conditions[field.identifier] = value; | |
} | |
// base validation of a field | |
public validateField(): boolean{ | |
console.log(this.value) | |
if(this.isRequired && (this.value == null || this.value == undefined)){ | |
return false | |
} | |
return true | |
} | |
} | |
// Plain Text box implementationf of a Field | |
class PlainTextField extends Field<string> { | |
private minSize: number | null; | |
private maxSize: number | null; | |
constructor(label: string, visible: boolean = true, minSize: number | null = null, maxSize: number | null = null){ | |
super(label, visible) | |
this.minSize = minSize; | |
this.maxSize = maxSize; | |
} | |
public override validateField(): boolean { | |
if(this.minSize == null && this.maxSize == null){ | |
return super.validateField(); | |
} | |
// Ensure min and max size of field is adhered to | |
if((this.minSize != null && this.value.length < this.minSize) || (this.maxSize != null && this.value.length > this.maxSize)){ | |
return false; | |
} | |
return true; | |
} | |
} | |
// Email field | |
class EmailTextField extends PlainTextField { | |
// stub format of POC | |
private format : RegExp = /.*@.*/; | |
public override validateField(): boolean { | |
return this.format.test(this.value) | |
} | |
} | |
// Single select field, contains an array of allowed values | |
// Assumes the selectable values are strings, could be numbers - wouldn't be too difficult to allow this | |
class SingleSelectField extends Field<string> { | |
public allowedValues: string[] | |
constructor(label: string, allowedValues: string[], visible: boolean = true){ | |
super(label, visible) | |
this.allowedValues = allowedValues; | |
} | |
public override validateField(): boolean { | |
if(!(this.value in this.allowedValues)){ | |
return false; | |
} | |
return true; | |
} | |
} | |
class BooleanField extends Field<boolean> { | |
constructor(label: string, defaultValue: boolean, visible: boolean = true){ | |
super(label, visible) | |
this.defaultValue = defaultValue; | |
} | |
} | |
class FileField extends Field<{}> { | |
// stub, assumbe that a FileField contains an object that represents a file | |
// would contain file temp location, or byte data, file type etc... | |
} | |
// Use the API | |
const form = new Form(); | |
const nameField = new PlainTextField("Name"); | |
form.addField(nameField); | |
const emailField = new EmailTextField("Email", false); | |
emailField.addConditional(nameField, "John Doe") | |
form.addField(emailField); | |
console.log(emailField.isVisible); //False | |
nameField.updateValue("John Doe"); | |
console.log(emailField.isVisible); //True | |
emailField.updateValue("jd"); | |
console.log(emailField.validateField()); //False | |
emailField.updateValue("[email protected]") | |
console.log(emailField.validateField()); //True | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment