ngx-mat-form-wizard
v0.0.8
Published
Angular Material JSON schema form generator
Downloads
6
Maintainers
Readme
Description
Ngx mat form wizard is a lightweight, fast and intuitive JSON-powered template-driven based machine that allows Angular developers to easily create and handle highly complex forms using a JSON schema.
Among the rest, the wizard includes some significant features:
- Responsive - It has an entire responsive grid that supports custom breakpoint, which is used to adjust your forms to any device.
- Auto-scroll - A built-in automatic smooth-scroll to an invalid field or group on submit attempt.
- Error management - The ability to control when your validations errors take effect.
- Nested forms - Divide your form into subforms(groups), and manage each of them individually.
- Events handling - Inject and use the powerful built-in "WizardEventBus", an RxJS subjects-based service that allows subscribing to any event that occurs in the wizard at run time.
- Custom validations - Implement any sync or async custom validation in the world for any input or group, using the unique "VALIDATE" event.
- Multiple validations - Provide multiple different error messages for each validation scenario, both for field or a group.
Out of the box functionality and styling is provided for Angular Material.
Motivation
During my career as a frontend software engineer, I have noticed how headache it can be to implement forms in your application. It requires quite a bit:
- Architecture - The endless comparison between the "template-driven" approach and the "reactive forms" can be frustrating sometimes. It can cost some precious time deciding what method suits your application the best, while both are not easy to learn for new developers.
- Validations - Implementation of complex validations can be a heavy task in some cases, and almost every form requires some of them. Wouldn't that be awesome if you only had some mechanism that could do this job for you?
- Infrastructure - Nowadays, almost every web application can also be used on our mobile devices. UI developers need to spend more time creating responsive forms, which can be adjusted to all kinds of screen sizes, and this was never a simple mission.
- Style - Creating a form isn't enough! It needs to be good-looking, attractive, and user-friendly. Styling your inputs to a professional level on your own can be challenging work! That's why I chose to make this package "Angular Material" Style based.
For such reasons, I decided to create this wizard and help developers benefit from my knowledge.
Table of contents
- Demo and source code
- Installation
- Setup
- Usage
- The ngx-mat-form-wizard
- Models
- Types
- Events handling with WizardEventBus
Demo and source code
Click here for a demo application on Heroku.
Click here to access the demo application's repository on GitHub, which you can also clone and run locally on your machine.
Installation
So first thing first, install the wizard in your project:
npm install ngx-mat-form-wizard
Or
yarn add ngx-mat-form-wizard
Setup
First, import the NgxMatFormWizardModule into your target module:
import { NgxMatFormWizardModule } from 'ngx-mat-form-wizard';
imports: [
NgxMatFormWizardModule,
// The rest of your imports ...
],
export class MyTargetModule { }
Next, choose one of Angular material themes and import it into your global styles file.
You may choose one of the followings: "purple-green", "pink-bluegrey", "indigo-pink", "deeppurple-amber"
@import "~@angular/material/prebuilt-themes/indigo-pink";
Click here to learn more about Angular material theming system.
Note: Don't forget to import BrowserAnimationsModule into your AppModule to enable Angular's animation system. Declining this will disable most of Angular Material's animations.
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
imports: [
BrowserAnimationsModule,
// The rest of your imports ...
],
export class AppModule { }
And that's it!!, your all setup and good to go ✌️
Usage
In your HTML file:
<ngx-mat-form-wizard
[groups]="groups"
[responsive]="true"
[autoscroll]="true"
[breakpoint]="625"
[errorState]="'when-submitted'"
(unsubmit)="handleUnsubmit($event)"
(onsubmit)="handleSubmit($event)">
</ngx-mat-form-wizard>
The ngx-mat-form-wizard
component
Hierarchy and technology
The wizard is based on the "Template Driven" technology and uses "Angular Material" as its source of functionality and styling.
In HTML terms, the wizard is one big <form>
tag that is built from three fundamental core elements:
Group
- A<form>
tag inside the wizard represented by theIWizGroup
object.Container
- A row/column inside the group represented by theIWizContainer
object.Field
- A input component inside the container represented by theIWizField
object.
Parameters
| Parameter | type | Description | Kind | Required | Default
| :---------- | :----------- | :---------------------------------------| :--------| :----------- | :----------- |
| id | string | Attach an ID for this wizard. | input | false | null
| submitText | string | Sets the text for the submit button. | input | false | 'Submit'
| fontFamily | string | Sets the font family of the wizard. | input | false | inherit
| fontSize | string | Sets the font size of the wizard. | input | false | inherit
| errorState | state
| Sets the error state of the wizard. | input | false | when-submitted
| breakpoint | number | Sets the breaking point for a responsive wizard. (in pixels) | input | false | 600
| dir | Direction
| Determine the direction of this wizard. | input | false | ltr
| offset | number | Pixels to offset from the top of the element when scrolling to. | input | false | 15
| autoscroll | boolean | When true, the wizard will support an automatic smooth-scroll to an invalid input on submit attempt. | input | false | false
| responsive | boolean | When true, this wizard will be responsive. | input | false | false
| hideSubmit | boolean | When true, there will be no submit button for the wizard. | input | false | false
| groups | Array<IWizGroup
> | An array of IWizGroup objects. | input | false | []
| onchange | EventEmitter<IWizGroup
[]> | Fires whenever some change occurs in the wizard. | output | |
| onsubmit | EventEmitter<IWizGroup
[]> | Fires whenever the wizard is successfully submitted. | output | |
| unsubmit | EventEmitter<IWizGroup
[]> | Fires whenever the wizard fails to submit. | output | |
API
remoteSubmit(): void - Use this function to submit the wizard remotely.
Models
The IWizGroup
model
The IWizGroup
object represents a group (<form>
) inside the wizard. The group can be used to divide your form into sections, while each group is independent and can be submitted and validated individually.
IWizGroup
properties are:
| Property | type | Description | Required | Default
| :---------- | :----------- | :----------------------------------------| :----------- | :----------- |
| id | string | Related unique ID of this form group. | false | null |
| validation | IWizValidation
| A validation notification to show when the group is invalid. | false | null
| headline | string | Related title for this form group. | false | null |
| style | style
| Sets the border style of the group. | false | solid |
| frameless | boolean | When true, this group will have no frame surrounding it, which means no padding or border. | false | false |
| color | string | Sets the color of the title and border. | false | border: #000000, title: inherit |
| events | boolean | When true, this entity will broadcast its events. | false | false |
| containers | Array<IWizContainer
> | An array of IWizContainer objects. | true | null |
The IWizContainer
model
The IWizContainer
object represents a row/column inside a group. It holds the input fields in horizontal or vertical view depending on the breaking point.
IWizContainer
properties are:
| Property | type | Description | Required | Default
| :---------- | :----------- | :----------------------------------------| :----------- | :----------- |
| id | string | Related unique ID of this container. | false | null |
| fields | Array<IWizField
> | An array of IWizField objects. | true | null |
The IWizField
model
The IWizField
object represents an input field inside a container.
IWizField
properties are:
| Property | type | Description | Required | Default
| :---------- | :------------ | :----------------------------------------| :----------- | :----------- |
| type | field
| Related type of the form field. | true | null |
| id | string | Related unique ID of the given field. | true | null |
| placeholder | string | Related placeholder. | false | null |
| innerPlaceholder | string | Related placeholder for a nested field. | false | 'Search...' |
| validation | IWizValidation
| A validation notification to show when the field is invalid. | false | null |
| hint | string | Provide some guidelines regarding this field. | false | null |
| dosubmit | boolean | When true, this button will submit its form or focus an invalid field. (applied for button field only) | false | false |
| theme | theme
| Select a style from the material design themes. (applied for button field only) | false | primary |
| files | Array | An array of File objects. | false | null |
| items | Array<IWizItem
> | An array of IWizItem objects. | false | null |
| selecteds | Array | An array of numbers represents the selected IWizItem objects. (applied in multiple selection fields only) | false | null |
| selected | number | The ID of the selected IWizItem object. (applied in single selection fields only) | false | null |
| value | string || number || boolean | Related value of the given field. (applied for text, number, or boolean fields) | false | null |
| date | Date | Related date of the given date field. | false | null |
| accept | string | Enable specific file formats to upload. (applied for files field only) | false | null |
| maxFileSize | number | Limit the maximum file size(in Bytes) to upload. (applied for files field only) | false | Infinity |
| maxTotalSize | number | Limit the maximum total files size(in Bytes) to upload. (applied for files field only) | false | Infinity |
| rows | number | Number of rows for textarea field. | false | null |
| cols | number | Number of columns for textarea field. | false | null |
| minNumber | number | Validate minimum number for number field. | false | null |
| maxNumber | number | Validate maximum number for number field. | false | null |
| minLength | number | Validate minimum characters length of a string. (applied to all text fields) | false | null |
| maxLength | number | Validate maximum characters length of a string. (applied to all text fields) | false | null |
| minItems | number | Validate minimum selected objects. | false | null |
| maxItems | number | Validate maximum selected objects. | false | null |
| minDate | Date | Limit the minimum date selection for the date field. | false | null |
| maxDate | Date | Limit the maximum date selection for the date field. | false | null |
| minDateOf | string | Provide an ID of another date field, used to limit the minimum date selection of the current date field by the date value of the other one. | false | null |
| maxDateOf | string | Provide an ID of another date field, used to limit the maximum date selection of the current date field by the date value of the other one. | false | null |
| pattern | string | Validate a regular expression for the given field. (applied for all text and number fields) | false | null |
| matchTo | string | Provide an ID of another field, used to validate a match between the current field's value to the value of the other one. | false | null |
| matchWith | string | Provide an ID of another field, used to validate a match between the current field's value with the value of the other one. | false | null |
| pending | boolean | When true, the field will show a progress indicator. | false | false
| hideQuantity | boolean | When true, the files field will not show the quantity of the selected files. | false | false
| multiple | boolean | When true, the files field will provide multiple selections. | false | false
| events | boolean | When true, this entity will broadcast its events. | false | false
| required | boolean | When true, this field will be required by the form validation. | false | false
| disabled | boolean | When true, this field will be frozen and inaccessible. | false | false
The IWizItem
model
The IWizItem
object represents an interface for a wizard item.
IWizItem
properties are:
| Property | type | Description | Required | Default
| :---------- | :----------- | :----------------------------------------| :----------- | :----------- |
| id | number | Related unique ID of this item. | true | null |
| name | string | Related label to show for this item. (supports innerHTML) | true | null |
| color | string | Sets the color of the lable and icon. | false | #000000 |
| icon | string | Choose one of angular material icons to show for this item. (not available in checklists components) | false | null |
| disabled | boolean | When true, this item will be frozen and inaccessible. | false | false |
The IWizValidation
model
The IWizValidation
object represents an interface for all validation types. You can show different error messages for each case or general error messages for all scenarios (using the "default" property).
| Property | type | Description | Required | Default | :---------- | :----------- | :----------------------------------------| :----------- | :----------- | | minLength | string | Provide an error message to show in case a string is too short. | false | null | maxLength | string | Provide an error message show in case a string is too long. | false | null | minNumber | string | Provide an error message to show in case a number is too small. | false | null | maxNumber | string | Provide an error message to show in case a number is too large. | false | null | isNan | string | Provide an error message to show in case a value is not a number. | false | null | minItems | string | Provide an error message to show in case there are less selected items than required. | false | null | maxItems | string | Provide an error message to show in case there are more selected items than required. | false | null | requireMatch | string | Provide an error message to show in case two fields are mismatched. | false | null | maxTotalSize | string | Provide an error message to show in case the total size of files is larger than required. | false | null | email | string | Provide an error message to show in case of an invalid email address. | false | null | pattern | string | Provide an error message to show in case the pattern is incorrect. | false | null | required | string | Provide an error message to show in case of a missing required value. | false | null | custom | string | Provide an error message to show in case a custom validation has been activated. | false | null | default | string | Provide some default error message to show in case there is no specific validation scenario. | false | null
Types
The state
type
A state
type determines how and when your wizard will show its validation errors.
| type | Description |
| :------------------------------ | :---------------------------------------|
| when-submitted | Show all validation errors only when the form has been submitted. (this is the default behavior)
| when-invalid | Instantly show all validation errors of all invalid inputs.
| when-touched | Show validation errors when the input has been touched or when the form has been submitted.
| when-pristine | Instantly show all validation errors only for pristine inputs or when the form has been submitted.
| when-dirty | Show validation error when the input is dirty or when the form has been submitted.
The Direction
type
A Direction
type determines the wizard's direction and all of its components, and it can be imported from @angular/cdk/bidi
.
import { Direction } from '@angular/cdk/bidi';
| type | Description | | :------------------------------ | :---------------------------------------| | ltr | Left to right. (this is the default behavior) | rtl | Right to left.
The style
type
A style
type is nothing more than the border style of the group.
You can choose one of the following:solid
| dashed
| dotted
| none
| unset
| hidden
| double
| groove
| ridge
| inset
| outset
| initial
| inherit
The theme
type
The theme
type allows you to style your group buttons with one of the following Material styles:primary
| basic
| warn
| accent
| disabled
| link
The field
type
The field
type is used to determine the type of input you are going to use.
Now let's discuss each of them individually:
text
The text
type is a simple text box where the user can edit strings and numbers.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, value
, minLength
, maxLength
, pattern
, matchTo
, matchWith
, events
, required
, disabled
| Events
| CHANGE
, FOCUS
, VALIDATE
number
The number
type is a simple numeric box where only numbers can be typed in.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, value
, minNumber
, maxNumber
, pattern
, matchTo
, matchWith
, events
, required
, disabled
| Events
| CHANGE
, FOCUS
, VALIDATE
password
The password
type provide a way to securely enter a password.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, value
, minLength
, maxLength
, pattern
, matchTo
, matchWith
, events
, required
, disabled
| Events
| CHANGE
, FOCUS
, VALIDATE
textarea
The textarea
type represents a multi-line plain-text editing control, useful when the user wants to enter a sizeable amount of free-form text.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, value
, minLength
, maxLength
, pattern
, rows
, cols
, events
, required
, disabled
| Events
| CHANGE
, FOCUS
, VALIDATE
email
The email
type defines a field for an e-mail address. The input value is automatically validated to ensure it is a properly formatted e-mail address.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, value
, events
, required
, disabled
| Events
| CHANGE
, FOCUS
, VALIDATE
search
The search
type also supports a progress spinner and a delayed CHANGE
event(650ms). It is comfortable to use where a search is needed.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, value
, pending
, minLength
, maxLength
, pattern
, matchTo
, matchWith
, events
, required
, disabled
| Events
| CHANGE
, FOCUS
, VALIDATE
date
The date
type create input field that let the user enter a date, the resulting value includes the year, month, and day.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, date
, minDate
, maxDate
, minDateOf
, maxDateOf
, events
, required
, disabled
| Events
| CHANGE
, TOGGLE
, VALIDATE
files
The files
type enables to upload any kind of file. It also displays the files list and enables files search and selection.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, files
, hideQuantity
, innerPlaceholder
, pending
, multiple
, accept
, maxFileSize
, maxTotalSize
, minItems
, maxItems
, events
, required
, disabled
| Events
| CHANGE
, TOGGLE
, SELECT
, SEARCH
, VALIDATE
single-select
The single-select
type represents a control that provides a menu of options and enables a single selection.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, items
, selected
, events
, required
, disabled
| Events
| CHANGE
, TOGGLE
, VALIDATE
multiple-select
The multiple-select
type represents a control that provides a menu of options and enables multiple selections.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, items
, selecteds
, minItems
, maxItems
, events
, required
, disabled
| Events
| CHANGE
, TOGGLE
, VALIDATE
autocomplete-single
The autocomplete-single
type represents a control that provides a menu of options and enables a single selection with autocomplete search.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, items
, selected
, innerPlaceholder
, pending
, events
, required
, disabled
| Events
| CHANGE
, SEARCH
, TOGGLE
, VALIDATE
autocomplete-multiple
The autocomplete-multiple
type represents a control that provides a menu of options and enables multiple selections with autocomplete search.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, hint
, items
, selecteds
, innerPlaceholder
, pending
, minItems
, maxItems
, events
, required
, disabled
| Events
| CHANGE
, SEARCH
, TOGGLE
, VALIDATE
checklist-single
The checklist-single
type represents a control that provides a list of radio buttons and enables a single selection. (note that the labels are innerHTML)
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, items
, selected
, events
, required
, disabled
| Events
| CHANGE
, VALIDATE
checklist-multiple
The checklist-multiple
type represents a control that provides a list of checkboxes and enables multiple selections. (note that the labels are innerHTML)
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, validation
, items
, selecteds
, minItems
, maxItems
, events
, required
, disabled
| Events
| CHANGE
, VALIDATE
content
The content
type is used to show any innerHTML content inside a group.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, value
, disabled
| Events
| no events available
button
The button
type represents a clickable button used to submit a group or just for accessible, standard button functionality.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
, placeholder
, dosubmit
, theme
, hint
, pending
, events
, disabled
| Events
| CLICK
void
The void
type is nothing. It can be used to create a blank space between inputs. Note that this element will be ceased to exist on a vertical view.
| Applied fields/events | Name |
| :---------------------------| :----------------------------|
| Fields
| type
, id
| Events
| no events available
Events handling with WizardEventBus
Any Group
or Field
entity has its events, and it's possible to subscribe to those events on your class constructor using a service called "WizardEventBus
". This service uses RxJS subjects as its core functionality. A subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast. You can read more about subjects here.
Field entity event types:
CHANGE
A CHANGE
event occurs every time the input field has changed its value.
Payload
{
field: IWizField, // The input field object.
formControl: formControl, // The associated form control.
content: any, // The new value.
}
FOCUS
A FOCUS
event occurs every time the input field has been focused or blurred.
Payload
{
field: IWizField, // The input field object.
formControl: formControl, // The associated form control.
content: FocusEvent // The focus event.
}
TOGGLE
A TOGGLE
event occurs every time the input field has been toggled.
Payload
{
field: IWizField, // The input field object.
formControl: formControl, // The associated form control.
content: boolean // Determine whether the input is open/closed.
}
SEARCH:
A SEARCH
event occurs when there is a change in the value of an inner search field.
Payload
{
field: IWizField, // The input field object.
formControl: formControl, // The associated form control.
content: string // The search keyword of the inner search field.
}
SELECT
A SELECT
event occurs when a file is selected from the dropdown menu of the files
input.
Payload
{
field: IWizField, // The input field object.
formControl: formControl, // The associated form control.
content: File // The selected file object.
}
CLICK
A CLICK
event can occur by clicking a group button or by clicking an innerHtml element.
Payload
{
field?: IWizField, // The input field object.
content: any // The associated data of the event.
}
VALIDATE
A VALIDATE
event occurs every time the input field's value is validated.
Payload
{
field: IWizField, // The input field object.
formControl: formControl, // The associated form control.
content: IWizValidate // Contains a boolean validation flag that allows triggering the validation manually.
}
Group entity event types:
CHANGE
A CHANGE
event occurs every time one of the group's fields has changed its value.
Payload:
{
group: IWizGroup, // The group object.
ngForm: ngForm, // The associated ngForm.
content: IWizField, // The input field object.
}
SUBMIT
A SUBMIT
event occurs when the group successfully submitted.
Payload:
{
group: IWizGroup, // The group object.
ngForm: ngForm, // The associated ngForm.
content: SubmitEvent // The submit event.
}
UNSUBMIT
A UNSUBMIT
event occurred when the group failed to submit.
Payload
{
group: IWizGroup, // The group object.
ngForm: ngForm, // The associated ngForm.
content: SubmitEvent // The submit event.
}
VALIDATE
A VALIDATE
event occurs every time the group's value is validated.
Payload:
{
group: IWizGroup, // The group object.
ngForm: ngForm, // The associated ng form.
content: IWizValidate // Contains a boolean validation flag that allows triggering the validation manually.
}
Subscribing events:
To subscribe to an event, we need to inject the WizardEventBus
service, call the "subscribe" method, and provide three parameters:id:
- (string) The id of the entity(field/group) we want to subscribe to.type:
- (WizardEventTypes) The type of the event we want to subscribe to.callback:
- (Function) Attach a function to call when the event occurs.
For example, let's subscribe to the CHANGE
event of a simple text field.
The IWizField
config object should look like that:
{
type: "text",
placeholder: "Enter your full name",
id: "full-user-name", // The unique id of the component.
events: true, // Enable events.
}
Note: remember to set the events
flag to true
.
In your ts file:
import { IWizData, WizardEventBus, WizardEventTypes, } from 'ngx-mat-form-wizard';
constructor(
private _wizardEventBus: WizardEventBus,
){
this._wizardEventBus.subscribe("full-user-name", WizardEventTypes.CHANGE, (event: IWizData) => {
// The `CHANGE` event occurs every time the input field has changed its value.
});
}
This way, we can subscribe to all the rest of the text field's available events:
import { IWizData, WizardEventBus, WizardEventTypes, } from 'ngx-mat-form-wizard';
constructor(
private _wizardEventBus: WizardEventBus,
){
this._wizardEventBus.subscribe("full-user-name", WizardEventTypes.FOCUS, (event: IWizData) => {
// The `FOCUS` event occurs every time the input field has been focused or blurred.
});
this._wizardEventBus.subscribe("full-user-name", WizardEventTypes.VALIDATE, (event: IWizData) => {
// The `VALIDATE` event occurs every time the input field’s value was validated.
});
}
Isn't that awesome? as you can see, it is easy to listen to any event using this service.
Note: remember to unsubscribe those subscriptions when the current view is destroyed. Watch the demo for examples.
InnerHTML events:
You can also subscribe to a 'CLICK' event of an innerHTML element. All you need to do is provide this element with a unique id and use the 'WizardEventBus' service. For example:
{
id: "accept-terms-and-conditions", // The unique id of the component.
type: "checklist-multiple",
events: true, // Enable events.
required: true // Define this field as required.
validation: {
required: "You must accept terms and conditions",
},
items: [
// the `IWizItem` object.
{
id: 4200, // The unique id of the item.
name: `
Please accept our
<span id="terms-and-conditions-link">
terms and conditions
</span>
before sign-in.
`
}
],
}
And in your ts file:
import { IWizData, WizardEventBus, WizardEventTypes, } from 'ngx-mat-form-wizard';
constructor(
private _wizardEventBus: WizardEventBus,
){
this._wizardEventBus.subscribe("terms-and-conditions-link", WizardEventTypes.CLICK, (event: IWizData) => {
// Your logic here...
});
}
Custom validations:
In some cases, you would like to implement your own custom sync/async validations in your form. For example, we want to use a text
type field with IP address validation attached to it. You can achieve that by subscribing to the "VALIDATE" event.
So first, let's set the config object for our field:
{
type: "text",
id: "user-ip-address", // The unique id of the component.
placeholder: "Enter your IP address",
events: true, // Enable events.
validation: {
custom: "Wrong IP address",
required: "This field is required"
},
required: true
},
Next, let's install a library that can do the IP address check for us and return a boolean value as a result. I have chosen to use the is-ip library for this example. (but you can use any other library or implement this functionality yourself)
npm i is-ip --save
Then, let's subscribe the VALIDATE
event in our class constructor and set the invalid
flag by the library's result:
import { IWizData, WizardEventBus, WizardEventTypes, } from 'ngx-mat-form-wizard';
import * as isIpAddress from 'is-ip';
constructor(
private _wizardEventBus: WizardEventBus,
){
this._wizardEventBus.subscribe("user-ip-address", WizardEventTypes.VALIDATE, (event: IWizData) => {
// This is the perfect place to implement your custom sync/async validations functionality and set the `invalid` flag as you wish.
event.content.invalid = !isIpAddress(String(event.field.value));
});
}
And that's it! The invalid
flag will be switched false/true by the response of the IP validator.
Now let's see another example. This time, we will implement a custom validation for a group, ready?
Let's suppose we want to have a group with four fields, and we would like the user to fill only 2 of them by his choice. Obviously, we cannot define all the fields as required, but we can make the group obligate the user to fill only two fields by a custom validation. So first, let's set our group config object:
{
id: "fill-only-2-fields-group", // The unique id of the component.
headline: "Choose Two Fields To Fill Up",
events: true, // Enable events.
validation: {
custom: "This group requires exactly 2 fields to be filled",
default: "This group has some issues"
},
containers: [
{
id: "name-and-email",
fields: [
{
type: "text",
id: "user-full-name",
placeholder: "Username",
pattern: "[a-zA-Z ]*",
minLength: 2,
maxLength: 8,
validation: {
maxLength: "Username should include up to 8 characters",
minLength: "Username should include at least 2 characters",
pattern: "Use upper/lower case letters only"
},
},
{
type: "email",
id: "user-email",
placeholder: "Email",
validation: "Invalid email",
validation: {
email: "Invalid email address",
},
},
]
},
{
id: "birthdate-and-docs",
fields: [
{
type: "date",
id: "user-birthdate",
placeholder: "Birthdate",
hint: "Verify that you are older than 18 years old",
maxDate: moment(moment().subtract(18, "year")).format("YYYY-MM-DD")
},
{
type: "files",
id: "user-docs",
validation: {
maxItems: "Please provide up to 5 files only",
minItems: "Please provide at least 2 files",
},
hint: "Up to 5MB per file.",
maxFileSize: 5000000,
accept: ".scss, .svg, .json, .gif, .html",
multiple: true,
minItems: 2,
maxItems: 5,
files: []
},
]
},
]
},
So those fields are not required, but they have their own validations that will still take effect if any value is inserted.
Then, we need to create the count-filled-values.validator.ts file:
import { FormGroup } from '@angular/forms';
export const countFilledValuesValidator = (formGroup: FormGroup, numberOfValues: number): boolean => {
return Object.keys(formGroup.controls).map((key: string) => {
const value: any = formGroup.controls[key].value;
return value != null && value != "";
}).filter(value => value).length == numberOfValues;
};
Next in our ts file, let's subscribe the VALIDATE
event in our class constructor and set the invalid
flag by the validator's result:
import { IWizData, WizardEventBus, WizardEventTypes, } from 'ngx-mat-form-wizard';
import { countFilledValuesValidator } from './count-filled-values.validator';
constructor(
private _wizardEventBus: WizardEventBus,
){
this._wizardEventBus.subscribe("fill-only-2-fields-group", WizardEventTypes.VALIDATE, (event: IWizData) => {
event.content.invalid = !countFilledValuesValidator(event.ngForm.form, 2) && event.ngForm.submitted;
});
}
Perfecto! so the group is now guided by our custom validator. Note that I also used the 'submitted' flag to prevent the group from showing its validation before submitting the form. (but that's also up to your scenario)
As you can see, the VALIDATE
event provides a boolean flag that can be toggled by your command and affect the validation state of the control. (this flag is a reference to an inner deep down nested local object, which is attached to the control's validation state)