@helios-interactive/reggie
v1.0.34
Published
Reggie, your form field butler.
Downloads
41
Keywords
Readme
Reggie
A plugin intent on making complex form flows simple, and easily changeable.
Installation
npm install @helios-interactive/reggie --save
Usage
To use Reggie, you need to have a target div on the page, and also need to configure Reggie.
Configuring Reggie
Reggie Accepts a configuration object on instantiation. This object is described here, and broken up by levels of nesting.
Reggie Top Level Options
|key|type|default|description|required| |---|---|---|---|---| |noSubmit|boolean|false|If set to true, then the reggie generated submit button will be hidden. It will still be present in the DOM to allow for form submission|false| |targetDiv|string||The ID of the target div. Reggie will generate the forms within this div.|true| |initial|string||The step that Reggie will start on. Should match the name of one of the defined steps|true| |formClasses|string||A string of all classes that should be added to the form when it is generated|false| |steps|array||The steps provided will determine what content the form collects, and in what order that content should be displayed. Reference the Step Options for details on configuring each of these.|
Step Options
|key|type|default|description|required|
|---|---|---|---|---|
|name|string||The name of this step. This must be unique, with no other step names matching it. This name is what you will use later when referencing the step for navigation flow.|true|
|next|string||The name of the step which should be transitioned to if reggieInstance.next()
is called.|false|
|submitButton|object||If a submit button is provided here, then it will overwrite the default submit button that reggie uses. It will overwrite for this step only. You can pass the class
(accepts a string, and can include multiple classes), and the text
which will be the text displayed within the button. Ex:{class: 'submit-btn', text: 'Submit'}
|false|
|pieces|array||Pieces defines each field that will be in this step of the form. Reference the Piece Options for details on configuring each of these.|true|
Piece Options
|key|type|default|description|required|
|---|---|---|---|---|
|name|string||The name of the piece. This should be unique for all pieces. When reggie constructs a model based on the form it will use the piece name to associate the input data with this piece.|true|
|type|string|'input'|The type of piece to be created. A list of available piece types can be found in the Piece Types section. |true|
|class|string||A string of all classes that should be added to the piece when it is generated|false|
|containerClass|string||Every piece has a container div that is created. All classes defined here will be added to the container div.|false|
|placeholder|string||If the piece type allows for placeholder text, then this text will become the placeholder|false|
|validations|array||Validations accepts an array of objects. Each object is a validation, and all validations will be run on a validation check. Each object must contain a regex
key and a error
key. The regex
key will be run against the value of the piece, and if it does not get a match, then an error will be triggered. The error
key contains the text of the error. Ex: {regex: /\w+/, error: 'Last name is required'}
|false|
|options|array||The options array is used when the piece type needs options (select, and radio). It will define what options are rendered in the piece.|sometimes - when type requires it. Reference the Piece-Options Options for details on configuring each of these.|
|pieces|array||If the piece type is declared to be 'group' then an additional array of pieces can be nested within the current piece. These pieces accept the same options as the current piece. This is primarily used for grouping elements together on the UI.|sometimes - when type requires it.|
|label|string||The text of the label that will be associated with the piece in the UI. If no text is present, then no label will be created. Labels also allow for the user to create a named span that can be refereced later, most commonly to treat it as a link. A label with the following { Text content, span-id }
syntax will create a span with the content being that which comes before the comma (trimmed), and the id being that which comes after the comma (trimmed).|false|
|labelClass|string||A string of all classes that should be added to the label when it is generated|false|
|autocomplete|boolean|true|If an input allows autocomplete, then this can be used to toggle that on or off.|false|
Piece-Options Options
|key|type|default|description|required|
|---|---|---|---|---|
|name|string||The name of the option. In a select piece, this will determine the text shown for the select option.|true|
|label|string||The text of the label that will be associated with the option in the UI. If no text is present, then no label will be created. If the parent piece is type select, then no label is shown. Labels also allow for the user to create a named span that can be refereced later, most commonly to treat it as a link. A label with the following { Text content, span-id }
syntax will create a span with the content being that which comes before the comma (trimmed), and the id being that which comes after the comma (trimmed). |false|
|labelClass|string||A string of all classes that should be added to the label when it is generated|false|
|value|any||The value of the piece if this option is choosen.|true|
|class|string||A string of all classes that should be added to the option when it is generated|false|
Piece Types
|type|description|requirements| |---|---|---| |group|A group piece allows for other pieces to be grouped within it. It will create a container div within the DOM to place all child pieces inside of. In this way you can break apart each step into sections within the DOM|A group type must have child pieces.| |radio|Creates a radio group with all of the given options as radio buttons|A radio type must have options that declare the radio butons.| |radio-pill|Creates a radio group with all of the given options as radio buttons.In addition, this radio group is styled in a pill shape with each option having a equal section of the pill.|A radio type must have options that declare the radio butons.| |input|This is the default input box|| |select|This will created a styled reggie select element.|A select type must have options that declare the select options.| |email|This will create an imput box of the type email.|| |checkbox|This will create a checkbox input.|| |tel|This will create an input box of the type tel.||
Using Reggie
Attributes
Attributes that are available on the reggie instance.
|attribute|description| |---|---| |model|A object defined by the pieces that are sent to reggie. This object is single level, and each key is associated with a piece. Each piece must be unique for the model to work properly. The model will be updated with the latest values from the pieces. The model can be accessed and updated directly using this attribute.| |options|The options sent to reggie on instantiation| |steps|The steps array from within the options sent to reggie|
Methods
|method|arguments|description|example|
|---|---|---|---|
|new|options - object. See Configuring Reggie|Creates and returns a new reggie instance.|new Reggie(reggieOptions)
|
|updateModel|form|Accepts a form, and will update the model based on the content of the form passed in.|reggie.updateModel(document.getElementById('reggie-form'))
|
|validateStep|form, updateDOM|Accepts a form (or defaults to the reggie form), and a boolean for updateDOM, if true, then validation errors will show in the DOM, if false, then errors will not be placed on the DOM. This method will run all validations for the current step, and return an array with any errors that are present. If no errors are present it will return an empty array.|if ( reggie.validateStep(null, false).length > 0 ) { alert('please correct the errors') };
|
|updateDOM||Forces a re-render of the reggie DOM. This can be used to incorporate model updates made by your app.|reggie.model.firstName = 'foobar'; reggie.updateDOM();
|
|currentStep||Returns the current step as an object|reggie.currentStep()
|
|currentAttributes||Returns an array of attributes that are in the currentStep|reggie.currentAttributes()
|
|next||Will go to the step defined in the current step's next attribute|reggie.next()
|
|previous||Will go to the previous step|reggie.previous()
|
|goto|target, recordTransition|Accepts a target (step name), and will render that step to the DOM. The second argument, recordTransition (boolean), will determine if this transition is recorded for use with the previous method. Will go to the given step name.|reggie.goto('lastStep')
|
|reset||Will reset reggie back to the initial state, and clear out the model to be empty again.|reggie.reset()
|
|submitStep||Will submit the current step|reggie.submitStep()
|
Events
Each event will provide a details
object that contains reggie specific information.
|event|details|description|
|---|---|---|
|reggieStepStart|{to: 'stepThatIsStarting', from: 'stepThatJustEnded', model: {contains: 'current snapshot of the model'}}
|Triggers at the beginning of a step, providign an update as to the current state.|
|reggieStepEnd|{to: 'stepThatIsStarting', from: 'stepThatJustEnded', model: {contains: 'current snapshot of the model'}}
|Triggers at the end of a step, providing an update as to the current state.|
|reggieStepSubmit|{from: 'stepThatJustEnded', model: {contains: 'current snapshot of the model'}}
|Triggers at the submission of a step, and allows the user to then direct what reggie should do next.|
Example Usage
const reggieOptions = {
noSubmit: false,
targetDiv: 'reggie-div',
initial: 'startStep',
formClasses: 'reggie-form',
steps: [
{
name: "startStep",
next: "finalStep",
submitButton: {
class: 'submit-btn',
text: 'Custom Submit Button'
},
pieces: [
{
type: "group",
class: "input-group",
pieces: [
{
name: "firstName",
type: "input",
autocomplete: false,
placeholder: "First Name",
class: 'input-box',
containerClass: 'container-class',
},
{
name: "lastName",
type: "input",
autocomplete: false,
placeholder: "Last Name",
class: 'input-box'
}
]
},
{
name: "email",
type: "email",
placeholder: "Email",
class: 'input-box',
containerClass: 'email-container'
}
]
},
{
name: "optionalStep",
next: "finalStep",
pieces: [
{
name: 'bestNumber',
type: 'select',
placeholder: 'Number 1-3',
label: 'Pick the best number.',
labelClass: 'reggie-label',
class: 'reggie-select',
options: [
{
name: '1',
value: '1'
},
{
name: '2',
value: '2'
},
{
name: '3',
value: '3'
}
]
}
]
}
{
name: "finalStep",
pieces: [
{
name: 'gender',
type: 'radio-pill',
class: 'reggie-radio-pillbox-custom',
options: [
{
name: 'male',
label: 'MALE',
value: 'male'
},
{
name: 'female',
label: 'FEMALE',
value: 'female'
},
{
name: 'unspecified',
label: 'UNSPECIFIED',
value: 'unspecified'
}
],
validations: [
{
regex: /\w+/,
error: 'Please select a gender'
}
]
},
{
name: 'over18',
type: 'checkbox',
containerClass: 'reggie-checkbox-container reggie-form-field',
class: 'reggie-checkbox',
label: 'I am at least 18 years old',
labelClass: 'reggie-label reggie-checkbox-label'
}
]
}
]
}
// Instantiate reggie, and draw the initial step into the DOM
const reggie = new Reggie(reggieOptions);
// Set default values for pieces
reggie.model.gender = 'unspecified';
// Update the DOM. You can do this when setting defaults so that they populate the
// current step. If the defaults pertain to a step that is yet to come, then they will
// automatically populate when that step is rendered.
reggie.updateDOM();
// Handle reggie submission events. You can control the flow of the form here
document.addEventListener('reggieStepSubmit', (event) => {
// if they are coming from the startStep, and provided an email
// then make them do the optional step
// Otherwise just call the step's given next option
if ( event.detail.from === 'startStep' && reggie.model.email ) {
reggie.goto("optionalStep");
} else {
reggie.next();
}
})
// Handle reggie step start events.
document.addEventListener('reggieStepSubmit', (event) => {
// If the user has completed all steps, then behave appropriately
if ( event.detail.to === 'done' ) {
let modelKeys = Object.keys(event.detail.model);
let finalModel = [];
modelKeys.forEach(key => {
finalModel.push(`${key}: ${event.detail.model[key]}`);
});
alert(`You made it through, here's your data!\n\n${finalModel.join('\n')}`);
}
}
License
MIT License
Copyright (c) [2017] [Adam McFadden]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.