-
Notifications
You must be signed in to change notification settings - Fork 34
Public Form
type Page = "personal-details" | "address" | "summary"
export class ApplicationComponent implements OnInit {
// Define your controller with the `Page` type defined above
_controller: PublicFormController<Page>
// Initialize your controller with the controller type
// details - a typical form
// list - when you have a list of many subitems ex. children
constructor(private router: Router) {
this._controller = new PublicFormController("details");
}
ngOnInit(): void {
(async () => {
// fetch your data
const req = await fetch("http://some_url/my-form")
const raw = await req.text();
this._controller.initState(item?.data || {}, () => {
this.formStatus = "complete";
this.showSpinner = false;
});
})();
}
}
export class ApplicationComponent implements OnInit {
// ...
handlePersonalDetails(e: Event): Page | undefined {
return "address";
}
handleAddress(e: Event): Page | undefined {
return "summary";
}
}
status
: (required) set to complete once external data is fetched
_complete
: *(required)*callback when last page is completed
_init
: (required) should be instantiated within controller
_stateChange
: (optional) allows you to incrementally save your data
<goa-public-form
[status]="formStatus"
(_complete)="onComplete()"
(_init)="_controller.init($event)"
(_stateChange)="updateState($event)"
<!-- content -->
</goa-public-form>
export class ApplicationComponent implements OnInit {
// set to complete in the _controller.initState callback
formStatus: "initializing" | "complete" = "initializing";
// ...
async updateState(e: Event) {
this._controller.updateObjectState(e);
// send state do your API here
}
onComplete() {
// called when the button on the last page of the form is clicked
}
}
id
: (required) An id defined within the Pages
type
_continue
: (required) Callback to trigger page handler functions. The second argument, must match the id
prop.
section-title
: (optional) Defines a section of the form
heading
: (optional) Heading text of the page. Most often used when more than one field exists on the page.
type
: (default: step) step | summary | multistep
The page type.
back-url
: (optional) If set, will result in navigating to the url when a user clicks the Back link instead of the default behaviour of navigating to the previous question page.
summary-heading
: (optional) Will be shown as a heading in the final summary page.
name
: (optional) The text displayed in the summary next to the value
label
: (optional) The text that will be displayed in the form
name
: (required) The name of the field that the value will be saved by within the JSON payload.
<goa-public-form ...>
<goa-public-form-page
id="personal-details"
section-title="Application"
heading="Personal details"
type="first-step"
back-url="/"
(_continue)="onPageChange($event, 'personal-details')"
>
<goa-fieldset>
<goa-form-item name="First name">
<goa-input name="first-name" />
</goa-form-item>
<goa-form-item name="Last name">
<goa-input name="last-name" />
</goa-form-item>
<goa-form-item label="SIN" name="Social insuance number">
<goa-input name="sin" />
</goa-form-item>
</goa-fieldset>
</goa-public-form-page>
<goa-public-form-page
id="address"
section-title="Application"
heading="Your current address"
type="step"
(_continue)="onPageChange($event, 'address')"
>
<goa-fieldset>
<goa-form-item name="Address">
<goa-input name="address" />
</goa-form-item>
<goa-form-item name="City/town">
<goa-input name="city" />
</goa-form-item>
<goa-form-item name="Postal code">
<goa-input name="postal-code" />
</goa-form-item>
</goa-fieldset>
</goa-public-form-page>
<goa-public-form-page
id="summary"
type="summary"
section-title="Application"
heading="Summary"
>
<goa-public-form-summary />
</goa-public-form-page>
</goa-public-form>
export class ApplicationComponent implements OnInit {
// ...
onPageChange(e: Event, from: Page) {
let dest: Page | undefined = undefined;
switch (from) {
case "personal-details":
this.handlePersonalDetails(e);
break;
case "address":
this.handleAddress(e);
break;
default:
console.warn("Unhandled page", from);
break;
}
if (dest) {
this._controller.continueTo(dest);
}
}
}
export class ApplicationComponent implements OnInit {
// ...
handlePersonalDetails(e: Event): Page | undefined {
const [firstNameOk, value] = this._controller.validate(e, "first-name", [
requiredValidator("First name is required"),
]);
const [lastNameOk, value] = this._controller.validate(e, "last-name", [
requiredValidator("Last name is required"),
]);
const [sinOk, value] = this._controller.validate(e, "sin", [
requiredValidator("Social insurance number is required"),
SINValidator(),
]);
if (!firstNameOk || !lastNameOk || !sinOk) {
// exist if invalid
return;
}
// if valid return the `id` of the page to progress to
return "address"
}
}
In the scenario that you need to obtain details for a one-to-many relationship you can use the <goa-sub-form>
to do so.
export class ApplicationComponent implements OnInit {
// Add child pages
type ChildPage = "name" | "dob" | "summary";
// The new children page set needs to be added to the
// top-level app's page list
type Page = "personal-details" | "address" | "children" | "summary"
// add child controller
_childController: PublicFormController<ChildPage>;
constructor(private router: Router) {
// instantiate child controller as a `list` type
this._childController = new PublicFormController("list");
}
// add child state change handler
updateChildrenState(e: Event) {
this._childFormController.updateListState(e);
}
// helper function to get list of children
children(): Record<string, string>[] {
return this._childController.getStateList();
}
}
id
: (required) Defines the inner form's id
_init
: (required) Same as PublicForm
_stateChange
: (optional) Same a PublicForm
<goa-public-form-page
id="children"
type="multistep"
(_continue)="onPageChange($event, 'children')"
>
<goa-public-subform
id="children-subform"
(_init)="_childController.initList($event)"
(_stateChange)="updateChildrenState($event)"
>
<goa-public-subform-index
slot="subform-index"
section-title="Child's profile"
heading="Child(ren)'s profile"
action-button-text="Add Child"
>
<goa-text mb="l" *ngIf="children().length === 0">
Include the child(ren) listed in your court order or agreement that you want MEP to enforce support for.
Select
‘Add child’ to start.
</goa-text>
<goa-table width="100%" mb="xl" *ngIf="children().length > 0">
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th></th>
<th></th>
</tr>
</thead>
<tr *ngFor="let item of children(); index as i">
<td>
{{ item["firstName"] }}
</td>
<td>
{{ item["lastName"] }}
</td>
<td class="goa-table-number-header">
<goa-link-button (_click)="_childController.edit(i)">Edit</goa-link-button>
</td>
<td class="goa-table-number-header" style="width: 0px">
<goa-link-button (_click)="showModal(i)">Delete</goa-link-button>
</td>
</tr>
</goa-table>
</goa-public-subform-index>
<goa-public-form-page
id="name"
section-title="Child's profile"
heading="Name"
sub-heading="Child's name"
button-text="Continue"
(_continue)="onChildPageChange($event, 'name')"
>
<goa-fieldset>
<goa-form-item name="First name" label="First name">
<goa-input name="firstName"></goa-input>
</goa-form-item>
<goa-form-item name="Middle name" label="Middle name">
<goa-input name="middleName"></goa-input>
</goa-form-item>
<goa-form-item name="Last name" label="Last name">
<goa-input name="lastName"></goa-input>
</goa-form-item>
</goa-fieldset>
</goa-public-form-page>
<goa-public-form-page
id="dob"
section-title="Child's profile"
heading="Your child's birthdate"
(_continue)="onChildPageChange($event, 'dob')"
>
<goa-fieldset>
<goa-form-item name="Date of birth" label="Date of birth">
<goa-date-picker type="input" name="dob"></goa-date-picker>
</goa-form-item>
</goa-fieldset>
</goa-public-form-page>
<goa-public-form-page
id="complete"
heading="Summary"
section-title="Child's profile"
type="summary"
button-text="Back to list"
>
<goa-public-form-summary></goa-public-form-summary>
</goa-public-form-page>
</goa-public-subform>
</goa-public-form-page>