In our previous blog post, we created a Dynamic Form using angular signal forms, that displayed different fields based on the selected account type.
In this blog post we will be looking at how we can submit our data to the backend, transforming our form model into the payload our backend expects, allowing our UI and API to have different data structures when needed.
Why transform our form data?
We designed our registration form based on what our user interface requirements were and not on the shape of our backend API.
export interface userAccount {
account: {
type: 'individual' | 'business';
individual: {
firstName: string;
lastName: string;
},
business: {
companyName: string;
taxId: string;
registrationNumber: string;
}
}
}
But what if our backend expects a totally different shape for our payload? For example:
export interface CreateAccountReq {
accountType: 'individual' | 'business';
firstName?: string;
lastName?: string;
companyName?: string;
taxId?: string;
registrationNumber?: string;
}
Instead of forcing our form model to match our backend request model, Angular recommends that we design our form around our user experience and translate it into what the backend requires, when we are ready to submit our data.
Let's see how we can do that.
Transforming Form Model to Backend Model
First we create a helper function to convert form model to backend api model:
import { CreateAccountReq, userAccount } from '../models/account';
export function formToRequest( form: userAccount ): CreateAccountReq {
if (form.account.type === 'individual') {
return {
accountType: 'individual',
firstName: form.account.individual.firstName,
lastName: form.account.individual.lastName,
}
}
return {
accountType: 'business',
companyName: form.account.business.companyName,
taxId: form.account.business.taxId,
registrationNumber: form.account.business.registrationNumber,
}
}
Submitting Form Data
Now that our helper function is ready, we make use of Angular Signal Form's submit() function. The submit function is built into the signal forms Api and helps you manage form submission lifecycles.
To submit our registrationForm, we manually create a submit method:
async onSubmit(event: Event) {
event.preventDefault();
const success = await submit(this.registerationForm, async (field) => {
const backendModel = formToRequest(this.field().value());
const result = await this.fakeBackendService.createAccount(backendModel);
if (result.ok) return;
return { kind: 'serverError', message: 'Failed to save' };
});
if (success) {
console.log("Account details submitted Successfully ...")
}else{
console.log("Unable to submit data ...")
}
}
In angular Signal Forms, since we are not using the template's FormRoot directive to submit the form but using the manual submission:
- We prevent the browser's default behavior by using the
preventDefault()so we can handle submission ourselves. - We then call the Signal Form's
submit()method and pass it two things:- The form we intend to submit.
- A callback that contains the code we want to run.
- The
submit()function resolves to true if successful submission and false if errors are returned.
NB: The callback passed to submit() will only execute if all fields pass validation. If any validation errors exist, the submission is stopped and the callback will not execute.
Top comments (0)