Skip to main content

Ajax Form

Ajax Forms combine form submission, API communication, and automatic response rendering. They allow you to submit without page reload, load entity data into inputs, and apply API responses directly to the UI.

Goals

  • Submit without page reload
  • Handle POST to PUT transitions
  • Render API responses into the DOM

Steps

Classes used in this pattern

ClassRole
CotomyApiFormAPI submit lifecycle
CotomyEntityApiFormPOST to PUT transitions using an entity key
CotomyEntityFillApiFormApply API responses to the UI

Form capabilities

FormAPI submitEntity keyRendererAuto fillNotes
CotomyFormNoNoNoNoSubmit lifecycle only
CotomyQueryFormNoNoNoNoGET query navigation
CotomyApiFormYesNoNoNoSends FormData to API
CotomyEntityApiFormYesYesNoNoPOST to PUT by entity key
CotomyEntityFillApiFormYesYesYesYesLoads and fills from API responses

1) Prepare HTML

<form id="profile-form" action="/api/profile" method="post">
<input name="name" />
<input name="email" />
<button type="submit">Save</button>

<div class="result">
<span data-cotomy-bind="name"></span>
<span data-cotomy-bind="email" data-cotomy-bindtype="mail"></span>
</div>
</form>

Inputs are for submission. Elements with data-cotomy-bind are for display. The same data flows into both.

2) Bind the form to Cotomy

import { CotomyEntityFillApiForm } from "cotomy";

const form = CotomyEntityFillApiForm.byId(
"profile-form",
CotomyEntityFillApiForm
)!;

form.initialize();

CotomyEntityFillApiForm submits with FormData and applies successful API responses to elements with data-cotomy-bind.

initialize() must be called once to enable Cotomy's submit lifecycle.

If the form already has an entity key, it automatically loads data when the page becomes ready.

3) Submit flow

When submitted:

  1. FormData is created
  2. The API request is sent
  3. If 201 Created, the entity key is stored
  4. Response JSON is applied to the DOM

This is a server-driven UI update model: the response is the source of truth.

4) POST to PUT transitions

When the server responds with 201 Created and a Location header, Cotomy stores the entity key. Subsequent submits switch from POST to PUT automatically.

Using the server-issued Location keeps identity authoritative and avoids duplicate creates in CRUD flows.

5) Bind name styles and renderers

data-cotomy-bind marks where values are rendered. data-cotomy-bindtype can format values (mail, tel, url, number, utc, date) during rendering.

<span data-cotomy-bind="email" data-cotomy-bindtype="mail"></span>

The renderer turns the value into a mail link automatically.

data-cotomy-bindtype only affects rendering, not form submission. For utc and date, rendering is local by default; add data-cotomy-timezone (element or ancestor) to render in a specific IANA timezone.

How Rendering Works

CotomyEntityFillApiForm uses CotomyViewRenderer internally. The renderer:

  • Reads JSON from the API response
  • Matches values to data-cotomy-bind
  • Updates the DOM elements

The renderer updates:

  • Elements with data-cotomy-bind
  • Matching form inputs (by name)

It does not modify unrelated DOM elements.

data-cotomy-bind is only used when a renderer is involved. Forms that do not use CotomyViewRenderer (such as plain CotomyForm or CotomyApiForm) will ignore these attributes.

Rendering does not change submission behavior. It only updates display elements and inputs. fill updates inputs; render updates display elements.

The renderer clears bound elements first, then applies data from the response. Keys that are missing in the response are cleared.

If the API request fails, rendering is skipped and error events are triggered.

6) Advanced: switch to dot notation

By default, Cotomy uses bracket-style bind names such as user[name]. If you prefer dot notation like user.name, set the page default bind name generator:

import {
CotomyDotBindNameGenerator,
CotomyEntityFillApiForm,
CotomyPageController
} from "cotomy";

CotomyPageController.set(class extends CotomyPageController {
protected override async initializeAsync(): Promise<void> {
this.defaultBindNameGenerator = new CotomyDotBindNameGenerator();

this.setForm(CotomyEntityFillApiForm.byId(
"profile-form",
CotomyEntityFillApiForm
)!);
}
});

Important Concept: Ajax Forms Use the Same DOM Model

Cotomy does not create a separate form state. Inputs and bound elements are still normal DOM nodes, and the API response is applied explicitly through the renderer.

What just happened?

You:

  1. Bound a form to Cotomy's API submit lifecycle
  2. Submitted without a page reload
  3. Switched to PUT after creation
  4. Applied API responses to the DOM

You now have a form that loads data, submits to an API, updates the UI, and manages entity identity.

Next

Next: Page Control to coordinate page-level behavior.