malsup/form
jQuery Form Plugin upgrades standard HTML forms to submit via AJAX with minimal setup. Use ajaxForm or ajaxSubmit to control how data is sent, handle responses, and manage options. Requires jQuery 1.7.2+, works with jQuery 2, partial jQuery 3 support.
## Getting Started
### Minimal Setup
1. **Include Dependencies**:
```html
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.3.0/jquery.form.min.js"></script>
Basic Form Submission:
<form id="myForm" action="/submit" method="post">
<input type="text" name="username">
<input type="submit" value="Submit">
</form>
<div id="results"></div>
$(document).ready(function() {
$('#myForm').ajaxForm({
target: '#results',
success: function() {
alert('Form submitted successfully!');
}
});
});
Manual Submission:
$('#myForm').on('submit', function(e) {
e.preventDefault();
$(this).ajaxSubmit({
url: '/submit',
dataType: 'json',
success: function(response) {
console.log('Success:', response);
}
});
});
AJAX-powered form submission without page reloads. Ideal for:
// Attach to all forms on page load
$('form.ajax-form').ajaxForm({
target: '#dynamic-content',
beforeSubmit: validateForm,
dataType: 'json'
});
Use Case: Global AJAX forms (e.g., admin panels, multi-step forms).
$('#submitBtn').on('click', function(e) {
e.preventDefault();
if (isValid()) {
$('#myForm').ajaxSubmit({
url: '/api/endpoint',
data: { extra: 'data' },
success: updateUI
});
}
});
Use Case: Forms with custom validation/logic before submission.
$('#fileForm').ajaxForm({
target: '#upload-status',
iframe: true, // Fallback for older browsers
uploadProgress: function(event, position, total, percentComplete) {
$('#progress-bar').css('width', percentComplete + '%');
}
});
Use Case: Drag-and-drop uploaders, large file handling.
// Update multiple targets based on response
$('#dynamicForm').ajaxSubmit({
target: function() {
return $('#response-' + $(this).data('type'));
},
success: function() {
$(this).find('input').val(''); // Clear form
}
});
Use Case: Modals, tabs, or multi-panel UIs.
CSRF Token Handling:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
resources/views/layouts/app.blade.php.Form Request Validation:
beforeSubmit: function(arr, $form, options) {
const errors = validateForm(arr);
if (errors.length) {
showErrors(errors);
return false; // Cancel submission
}
}
Laravel Routes:
url: "{{ route('form.submit') }}",
Response Handling:
success: function(response) {
if (response.errors) {
showFlashMessage('Error', response.errors, 'danger');
} else {
showFlashMessage('Success', response.message, 'success');
}
}
target: '#form-container > .form-section' to update specific sections.$('#step1').ajaxSubmit({
success: function() {
$('#step2').ajaxSubmit({ /* ... */ });
}
});
uploadProgress: function(event, position, total) {
Laravel.echo.channel('form-uploads')
.listen('Progress', (e) => {
console.log('Server progress:', e.percent);
});
}
jQuery Version Conflicts:
jquery.form.min.js from v4.3.0+ or polyfill missing methods.$.param behavior changed in jQuery 3.0+ (see #521).File Uploads in Modern Browsers:
iframe fallback triggers even with XHR2 support.iframe: false for non-file forms:
$('#nonFileForm').ajaxForm({ iframe: false });
CSRF Token Mismatch:
419 (CSRF token mismatch) despite token inclusion.beforeSubmit: function() {
$.post('/sanctum/csrf-cookie').then(() => {
// Proceed with submission
});
}
Form Data Serialization:
+, spaces) are not URL-encoded.encode: true (default) or manually encode:
data: { search: encodeURIComponent($('#query').val()) }
Event Delegation:
delegation: true.$(document).on('submit', 'form.dynamic-form', function(e) {
e.preventDefault();
$(this).ajaxSubmit({ /* ... */ });
});
Check the jqxhr Object:
var jqxhr = $('#myForm').ajaxSubmit({ /* ... */ });
jqxhr.fail(function(jqXHR, textStatus, errorThrown) {
console.error('Error:', textStatus, errorThrown);
console.log('Response:', jqXHR.responseText);
});
Inspect Form Data:
beforeSubmit: function(arr, $form) {
console.log('Submitting:', $.param(arr));
}
Test with iframe: true:
$('#myForm').ajaxSubmit({ iframe: true, iframeSrc: 'javascript:false;' });
Laravel Logs:
storage/logs/laravel.log for server-side errors (e.g., validation failures).target vs. replaceTarget:
target: '#container' replaces content.target: '#container', replaceTarget: true replaces the element itself.dataType Handling:
dataType: 'json':
success: function(response) {
console.log(response.data); // Access nested data
}
clearForm vs. resetForm:
clearForm: true clears visible fields (not hidden inputs).resetForm: true resets all fields (including hidden ones).beforeSerialize vs. beforeSubmit:
beforeSerialize: Modify form structure (e.g., hide fields).beforeSubmit: Modify data (e.g., transform values).Custom Serialization:
Override formSerialize for non-standard forms:
$.fn.formSerialize = function() {
// Custom logic
return $.param(this.serializeArray());
};
Progress Events: Extend upload progress with custom metrics:
uploadProgress: function(event, position, total) {
const speed = (position / (event.timeStamp - event.startTime)) * 1000;
console.log('Speed:', speed.toFixed(2), 'B/s');
}
Laravel Service Integration:
success: function(response) {
if (response.redirect) {
window.location.href = response.redirect;
}
// Trigger Laravel Echo events
Laravel.echo.channel('notifications')
.trigger('form-submitted', response);
}
Conditional Plugin Initialization:
if ($.fn.jquery.match(/^\d+\.\d+\.\d+$/
How can I help you explore Laravel packages today?