Dirty Fields & PATCH Requests
Track which fields have changed since the last save and send only the modified data to the server. The save button is disabled when no changes have been made.
What this example covers:
- Getting only changed fields with
form.getDirtyFields() - Per-field dirty tracking with
getFieldState().isDirty - Form-level dirty state with
getFormState().isDirty - Disabling submit when nothing changed
- Resetting defaults after save
Live Demo
JavaScript
getDirtyFields() returns an object with only the fields that differ from their defaults. After a successful save, call reset() with the current values to make them the new baseline.
js
Alpine.data('dirtyFieldsForm', () => ({
result: '',
showResult: false,
form: Alpine.Form({ name: 'John', email: 'john@example.com', bio: '' }),
handleSubmit() {
const dirty = this.form.getDirtyFields();
if (Object.keys(dirty).length === 0) {
this.showResult = true;
this.result = 'No changes to save';
return;
}
this.showResult = true;
this.result = 'Saving only changed fields:\n' + JSON.stringify(Alpine.raw(dirty), null, 2);
this.form.reset({ ...Alpine.raw(this.form.getValue()) });
},
}));HTML
Each field label shows a "modified" badge when dirty. The submit button is disabled via :disabled="!form.getFormState().isDirty". A live preview of dirty fields is shown below the form.
html
<p style="color: #64748b; font-size: 14px; margin-top: 0">
Edit some fields and submit. Only the changed fields are sent. Save button is disabled when
nothing changed.
</p>
<div x-data="dirtyFieldsForm">
<form @submit.prevent="handleSubmit()">
<div class="field-group">
<label>
Name
<span class="dirty-badge" x-show="form.getFieldState('name').isDirty"
>modified</span
>
</label>
<input x-register:form="form.field('name')" type="text" />
</div>
<div class="field-group">
<label>
Email
<span class="dirty-badge" x-show="form.getFieldState('email').isDirty"
>modified</span
>
</label>
<input x-register:form="form.field('email')" type="email" />
</div>
<div class="field-group">
<label>
Bio
<span class="dirty-badge" x-show="form.getFieldState('bio').isDirty">modified</span>
</label>
<textarea
x-register:form="form.field('bio')"
placeholder="Write something..."
></textarea>
</div>
<div class="btn-group">
<button type="submit" :disabled="!form.getFormState().isDirty">Save Changes</button>
<button type="button" @click="form.reset()">Discard</button>
</div>
</form>
<pre x-show="showResult" x-text="result"></pre>
<pre x-text="'Dirty fields: ' + JSON.stringify(form.getDirtyFields(), null, 2)"></pre>
</div>How Dirty Tracking Works
isDirty compares against defaults — changing a value back to its original clears the flag:
js
// form starts with { name: 'John' }
form.setValue('name', 'Jane');
form.getFieldState('name').isDirty; // true
form.setValue('name', 'John');
form.getFieldState('name').isDirty; // false (back to default)