cicil-forms
v0.2.7
Published
This is a repo which gives you ability to create complex forms by just providing JSON object of fields that you require in the form, these forms are based on carbon design
Downloads
8
Maintainers
Readme
Welcome to generic form component
This is a form component widget that can be used to create simple and moderately complex forms as per the carbon design standards
[Live codesandbox demo]: https://codesandbox.io/s/cicil-forms-example-sjclkm
[NPM package]: https://www.npmjs.com/package/cicil-forms
Usage
<Form
id={<String id here>}
elements={<Array of individual form fields>}
sectionName={<Name of form section>}
formData={<Object (key-value) of final form values>}
updateFormData={<function where we get the form field changes}
isEditMode={<Boolean that specifies whether form is in edit mode or new mode>}
></Form>
Props reference
The component takes the following props.
| Prop | Type | Description |
|-------------------|------------|-------------|
| id
| String | This is unique string id, important for differentiation between multiple FormComponent
invoked in a single view |
| elements
| Array | Form fields array structure|
| formData
| Object | key-value pairs, note: the key names should match the indivisual form field key: name
|
| updateFormData
| Function | This is a debounced function that is called when ever user changes any data in any of the form field |
| isEditMode
| Boolean | This is a boolean, if true
, it will take the formData
and prefill the form fields for all non-empty keys in formData
, which will make the form work as editing mode, if false
then new empty form will be presented to the user |
| sectionName
| String | This is a boolean, if true
, it will take the formData
and prefill the form fields for all non-empty keys in formData
, which will make the form work as editing mode, if false
then new empty form will be presented to the user |
Form fields array structure ( JSON Schema ) [ TODO ]
export interface FormField {
widgetLabel: string
/**
* TextInput | Select | TextArea | RadioButtonGroup | CheckboxGroup | ComboBox | MultiSelect | Checkbox | DatePicker | NumberInput
*/
widgetType: string
/**
* This key: name will be
* used to create form payload
* e.g if named: 'age', the formData becomes { age: 'value' }
*/
name: string
/**
* This key dictates whether to show
* the position of the field. eg left colum or right column
* Left column - 1
* Right column - 2
* Top column - 0
* Common (across both columns) - 3
* Top right column - 4
*/
columnNum?: number
/**
* if `true` then loader is added to the field
*/
loading?: boolean
/**
* if `true` then triggers the
* error styling and applies the invalidText, requiredValidationMessage keys
*/
invalid?: boolean
/**
* Max number of characters which can be entered
*/
maxLength?: number
/**
* if `true` then this field is visible on the form/screen,
* if `false` then the this particular field is no more
* visible in the form
*/
visible?: boolean
/**
* if `true` then this field becomes compulsory field,
* else is treated as optional fields
*/
required?: boolean
/**
* if the field is a required: true field
* and no data is entered then this message is
* displayed to the user
*/
requiredValidationMessage?: string
/**
* This message will be displayed to user if entered
* data does not match/satisfy the validation
* rules declared for this field
*/
invalidText?: string
/**
* if `true` then this field is shown in Preview,
* else it is not shown
*/
showInPreview?: boolean
/**
* If `true`, when onBlur event is called where field has
* some value entered that satisfies the validation rules,
* then func: `apiValidateFunc` is called to
* validate the data by executing the function
*/
shouldValidateByApi?: boolean
/**
* If `true`, when form is rendered on screen
* the func: `prefecthFunc` if called where
* we cann put initial data loading logic,
* e.g. loading states, countries, timezones etc...
*/
shouldPrefetch?: boolean
/**
* If `true`, when form is rendered in edit mode,
* where the value for this field is prefilled,
* then the user is no more allowed to change
* the value of this field
*/
preFetchPayloadKeys?: Array
/**
* Takes an array of keys as input and returns an array of
* objects by getting the value of these keys from the existing
* payload, This is then passed as the payload to the prefetch function.
*/
disableOnEdit?: boolean
/**
* If `true`, then this field will be disabled,
* and user can no more change the data in this field
*/
disabled?: boolean,
/**
* If set of Label/checkbox to `true`, it allows to load html tags in the labels
*/
setLabelWithFormatting?: boolean
/**
* If `true`, then onload of the form, it runs the APIVAlidateFunc for this field
*/
runApiValidateFuncByDefault?: true,
/**
* If `shouldValidateByApi` is `true`, then this function
* is executed, note: we can use this.keyNameOfThisField
* to mutate any property of this field like clearing off
* the loaders etc... and at the end we need to return
*
* return Promise.resolve(this);
*
* OR
*
* this.responseError = error
return Promise.resolve(this);
*/
apiValidateFunc?: async () => {},
/**
* If `shouldPrefetch` is `true`, then this function
* is executed, note: we can use this.keyNameOfThisField
* to mutate any property of this field like clearing off
* the loaders etc... and at the end we need to return
*
* return Promise.resolve(this);
*
* OR
*
* this.responseError = error
return Promise.resolve(this);
*/
prefetchFunc?: async () => {},
/**
* If `true`, all the fields mentioned in dependentFields would be
* updated ( action is updateValue), prefetchFunc func would be called
* if action is prefetchValue.
*/
runDependentFields?: boolean,
/**
* define all the fields that need to be updated/prefetched.
* eg - { fieldName: "CompanyName", action: "updateValue" },
* { fieldName: "FirstName", action: "prefetchFunc" },
*/
dependentField?s: JSON Array,
/**
* set the response from API in prefetch, so that it can
* be used to set back to the payload
*/
response?: JSON,
/**
* In case of errors, we can set the responseError option
*/
responseError?: String,
/**
* If `true`, the response values would be updated on the payload
*/
this.updatePayload?: true,
/**
* If this is set, the passed in values are set on paylaod
* { State: selectedState, StateCode: "" };
*/
this.multiKeyValueResponse?: JSON,
/**
* If `true`, `i` icon will be shown after label,
* where if hovered `tooltipHelpText` will be
* displayed
*/
tooltip?: false,
/**
* Set the tooltip text that needs to be shown
*/
tooltipHelpText?: string,
/**
* Set the tooltip text that needs to be shown
*/
}
{
widgetLabel: "Address line2",
widgetType: "TextInput",
name: "AddressLine2",
columnNum: 1,
maxLength: 100,
required: false,
visible: true,
requiredValidationMessage: "form.RequiredValidationMessage"
},
{
widgetLabel: "Country or origin",
widgetType: "Select",
name: "Country",
options: [],
initialSelectedItem: {
value: "US",
text: "US"
},
columnNum: 2,
dependentFields: [
{ fieldName: "State", action: "prefetchValue, updateValue" }
// { fieldName: "StateCode", action: "prefetchValue, updateValue" }
],
async prefetchFunc(ccode = "US") {
let payload = {};
if (!ccode || ccode === "") {
ccode = "US";
}
try {
let response = await axiosWithTokenRefresh("get", {
url: `${endpoints.GET_COUNTRIES_LIST}/${ccode}`,
payload
});
if (response.data.status === 200) {
this.options = response.data.Countries;
this.options.forEach((opt) => {
if (opt.value === ccode) {
this.selectedItem = opt;
}
});
this.loading = false;
this.invalid = false;
this.response = response;
this.runDependentFields = true;
this.shouldPrefetch = false;
}
return Promise.resolve(this);
} catch (error) {
this.loading = false;
this.invalid = true;
this.invalidText = "Failed to load countries, refresh and try again!";
this.responseError = error?.response.data.message || error.toString();
return Promise.resolve(this);
}
}
{
widgetLabel: "Decline invitation",
widgetType: "TextArea",
name: "declineInvitationMsg",
columnNum: 3,
step: 0,
invalid: false,
maxLength: 128,
visible: true,
required: false,
requiredValidationMessage: "Enter a valid message to send to the administrator",
invalidText: "Email a valid message to send to the administrator",
shouldValidateByApi: false,
shouldPrefetch: true,
disableOnEdit: false,
replacementText: "",
tabIndex: 1,
async apiValidateFunc() {},
async prefetchFunc(value, initialDepSelection, inputpayload) {
this.replacementText = inputpayload?.EmailAddress;
this.shouldPrefetch = false;
return Promise.resolve(this);
}
},
TODO
{
widgetType: "CheckboxGroup",
widgetLabel: "Please select all that apply regarding the prospect’s business:",
name: "checkboxOptions",
useLabel: true,
label: "Please select all that apply regarding the prospect’s business:",
columnNum: 1,
visible: true,
required: true,
options: [
{
text: "Telecommunications",
name: "Telecommunications",
checked: false
},
{
text: "Internet Service Provider(ISP)",
name: "InternetServiceProvider",
checked: false
},
{
widgetLabel: "Charge agreement number",
widgetType: "ComboBo",
name: "ChargeAgreementNum",
columnNum: 2,
required: true,
visible: true,
maxLength: 10,
options: [],
selectedItem: {
text:"Please select", value:"select"
}
}
TODO
{
widgetLabel:
"I have received confirmation from the client that they have agreed to IBM Security Randori Trial Terms for an ASR",
widgetType: "Checkbox",
useLabel: true,
name: "CustomerAuthorizedASR",
setLabelWithFormatting: true,
columnNum: 3,
invalid: false,
required: true,
requiredValidationMessage: "Select the checkbox",
invalidText: "Select the checkbox",
},
{
widgetLabel: "Beta End Date",
widgetType: "DatePicker",
invalid: false,
name: "betaEndDate",
columnNum: 2,
tooltip: true,
tooltipHelpText: "form.betaEndDateHelp",
}
{
widgetLabel: "Quantity",
widgetType: "NumberInput",
name: "Quantity",
maxLength: 128,
required: true,
hideLabel: true,
invalidText: "",
shouldValidateByApi: false,
shouldPrefetch: false,
min: 0,
max: 2147483647,
initialValue: 1,
async apiValidateFunc() {}
},
{
widgetLabel: "Label",
//useLabel: true,
widgetType: "Label",
name: "formDetails",
setLabelWithFormatting: true,
columnNum: 3,
step: 0,
value:
"Per the changes in the <a target='_blank' href=''>ASR process</a>, this form discloses how Randori collects and maintains data in the cloud for up to 30-days.",
async prefetchFunc() {},
async apiValidateFunc() {}
},