Documentation
Forms
Documentation on forms
Nitrokit is a boilerplate designed to help developers ship Angular applications faster, focusing on reducing boilerplate code. Nitrokit leverages ngx-vest-forms for form validation, using Vest.js behind the scenes to handle asynchronous and reusable form validation. It integrates seamlessly with Angular's template-driven forms, enabling developers to create powerful, complex forms with minimal configuration and hassle.
Key Features
- Quick and easy setup for Angular applications.
- Seamless form validation using
ngx-vest-forms
andvest.js
. - Template-driven forms with unidirectional data flow.
- Automatic creation and validation of form controls and groups.
- Support for conditional validations, composable validations, and more.
Getting Started with Forms
With Nitrokit, you can quickly set up forms with built-in validation powered by ngx-vest-forms
and Vest.js
. Below is an example that demonstrates how to create a form with Nitrokit:
Step 1: Create a Basic Form
In this example, we'll create a form with two fields: firstName
and lastName
.
- Import the
vestForms
directive fromngx-vest-forms
into your component. - Apply the
scVestForm
directive to the form, listen for form changes, and handle form submission.
import { vestForms, DeepPartial } from 'ngx-vest-forms';
type MyFormModel = DeepPartial<{
generalInfo: {
firstName: string;
lastName: string;
};
}>;
@Component({
imports: [vestForms],
template: `
<form scVestForm
(formValueChange)="formValue.set($event)"
(ngSubmit)="onSubmit()">
<div ngModelGroup="generalInfo">
<label>First name</label>
<input type="text" name="firstName" [ngModel]="formValue().generalInfo?.firstName"/>
<label>Last name</label>
<input type="text" name="lastName" [ngModel]="formValue().generalInfo?.lastName"/>
</div>
</form>
`
})
export class MyComponent {
protected readonly formValue = signal<MyFormModel>({});
onSubmit() {
console.log(this.formValue());
}
}
Step 2: Add Validation
To add validation, define a Vest.js validation suite and pass it to the form. This suite defines the validation logic for the form fields.
import { enforce, staticSuite, test } from 'vest';
export const myFormModelSuite = staticSuite((model: MyFormModel, field?: string) => {
if (field) {
only(field);
}
test('firstName', 'First name is required', () => {
enforce(model.firstName).isNotBlank();
});
test('lastName', 'Last name is required', () => {
enforce(model.lastName).isNotBlank();
});
});
Bind this suite to your form component:
@Component({
...
template: `
<form scVestForm
[suite]="myFormModelSuite"
(formValueChange)="formValue.set($event)"
(ngSubmit)="onSubmit()">
<div ngModelGroup="generalInfo">
<label>First name</label>
<input type="text" name="firstName" [ngModel]="formValue().generalInfo?.firstName"/>
<label>Last name</label>
<input type="text" name="lastName" [ngModel]="formValue().generalInfo?.lastName"/>
</div>
</form>
`
})
export class MyComponent {
protected readonly formValue = signal<MyFormModel>({});
protected readonly suite = myFormModelSuite;
}
Now, whenever the user types into the form, validation will trigger automatically, and any validation errors will be managed by the form controls.
Advanced Features
Conditional Fields
Using computed signals, you can easily show or hide form fields based on conditions in the form. For instance, to hide the lastName
field if firstName
is not filled out:
class MyComponent {
...
protected readonly lastNameAvailable = computed(() => !!this.formValue().generalInfo?.firstName);
}
<div ngModelGroup="generalInfo">
<label>First name</label>
<input type="text" name="firstName" [ngModel]="formValue().generalInfo?.firstName"/>
@if(lastNameAvailable()) {
<label>Last name</label>
<input type="text" name="lastName" [ngModel]="formValue().generalInfo?.lastName"/>
}
</div>
Composable Validations
Vest allows you to compose validation suites, making it easier to reuse validation logic for form fields or groups. For example, you can create a reusable address validation suite and include it in different parts of your forms.
export function addressValidations(model: AddressModel | undefined, field: string): void {
test(`${field}.street`, 'Street is required', () => {
enforce(model?.street).isNotBlank();
});
// Other address-related validations...
}
export const myFormSuite = staticSuite((model: MyFormModel, field?: string) => {
if (field) {
only(field);
}
addressValidations(model.address, 'address');
});
Reactive Disabling
You can also dynamically enable or disable form fields based on the state of other form fields using computed signals. For example, disable the lastName
field if firstName
is not filled:
class MyComponent {
protected readonly lastNameDisabled = computed(() => !this.formValue().generalInfo?.firstName);
}
<input type="text" name="lastName" [disabled]="lastNameDisabled()" [ngModel]="formValue().generalInfo?.lastName"/>
Showing Validation Errors
With Nitrokit, you can automatically show validation errors using the sc-control-wrapper
directive. This directive helps manage validation errors on blur and form submission.
<div ngModelGroup="generalInfo" sc-control-wrapper>
<div sc-control-wrapper>
<label>First name</label>
<input type="text" name="firstName" [ngModel]="formValue().generalInfo?.firstName"/>
</div>
<div sc-control-wrapper>
<label>Last name</label>
<input type="text" name="lastName" [ngModel]="formValue().generalInfo?.lastName"/>
</div>
</div>
Complex Validations
Nitrokit simplifies handling complex validations, such as dependent field validations (e.g., password and confirm password) and cross-field validations.
For example:
test('passwords.password', 'Password is required', () => {
enforce(model.passwords?.password).isNotBlank();
});
omitWhen(!model.passwords?.password, () => {
test('passwords.confirmPassword', 'Confirm password is required', () => {
enforce(model.passwords?.confirmPassword).isNotBlank();
});
});
omitWhen(!model.passwords?.password || !model.passwords?.confirmPassword, () => {
test('passwords', 'Passwords do not match', () => {
enforce(model.passwords?.confirmPassword).equals(model.passwords?.password);
});
});
Conclusion
Nitrokit streamlines the process of building and validating forms in Angular applications. By using ngx-vest-forms
and Vest.js, Nitrokit removes much of the manual work involved in form handling and validation, allowing you to focus on building robust applications.
Examples
Check out the examples provided in the GitHub repository to see Nitrokit in action:
Explore these examples to see how Nitrokit handles complex forms, including conditional validations, form arrays, and reusable components.
Want to Learn More?
For a deeper dive into complex Angular forms, check out this course that will guide you through creating advanced forms in Angular.
Have questions?
Still have questions? Talk to support.