Refactor designer, manufacturer, and ride model forms to utilize Alpine.js for state management. Improved form submission handling, HTMX event integration, and enhanced user experience through better event dispatching and modal management.

This commit is contained in:
pacnpal
2025-09-26 14:34:59 -04:00
parent 5b7b203619
commit 09e2c69493
3 changed files with 206 additions and 94 deletions

View File

@@ -1,35 +1,66 @@
{% load static %} {% load static %}
<form method="post" <script>
class="space-y-6" document.addEventListener('alpine:init', () => {
x-data="{ submitting: false }" Alpine.data('designerForm', () => ({
@submit.prevent=" submitting: false,
if (!submitting) {
submitting = true; init() {
const formData = new FormData($event.target); // Listen for HTMX events on this form
this.$el.addEventListener('htmx:afterRequest', (event) => {
if (event.detail.pathInfo.requestPath === '/rides/designers/create/') {
this.handleResponse(event);
}
});
},
async submitForm(event) {
if (this.submitting) return;
this.submitting = true;
const formData = new FormData(event.target);
const csrfToken = this.$el.querySelector('[name=csrfmiddlewaretoken]').value;
// Use HTMX for form submission
htmx.ajax('POST', '/rides/designers/create/', { htmx.ajax('POST', '/rides/designers/create/', {
values: Object.fromEntries(formData), values: Object.fromEntries(formData),
headers: { headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value 'X-CSRFToken': csrfToken
} },
target: this.$el,
swap: 'none'
}); });
},
// Handle HTMX response using event listeners handleResponse(event) {
document.addEventListener('htmx:afterRequest', function handleResponse(event) { this.submitting = false;
if (event.detail.pathInfo.requestPath === '/rides/designers/create/') {
document.removeEventListener('htmx:afterRequest', handleResponse);
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) { if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) {
const data = JSON.parse(event.detail.xhr.response); const data = JSON.parse(event.detail.xhr.response);
if (typeof selectDesigner === 'function') {
selectDesigner(data.id, data.name); // Dispatch event with designer data for parent components
} this.$dispatch('designer-created', {
$dispatch('close-designer-modal'); id: data.id,
} name: data.name
submitting = false; });
}
}); // Close modal if in modal context
}"> this.$dispatch('close-designer-modal');
} else {
// Handle error case
this.$dispatch('designer-creation-error', {
error: event.detail.xhr.responseText
});
}
}
}));
});
</script>
<form method="post"
class="space-y-6"
x-data="designerForm()"
@submit.prevent="submitForm($event)">
{% csrf_token %} {% csrf_token %}
<div id="designer-form-notification"></div> <div id="designer-form-notification"></div>

View File

@@ -1,35 +1,66 @@
{% load static %} {% load static %}
<form method="post" <script>
class="space-y-6" document.addEventListener('alpine:init', () => {
x-data="{ submitting: false }" Alpine.data('manufacturerForm', () => ({
@submit.prevent=" submitting: false,
if (!submitting) {
submitting = true; init() {
const formData = new FormData($event.target); // Listen for HTMX events on this form
this.$el.addEventListener('htmx:afterRequest', (event) => {
if (event.detail.pathInfo.requestPath === '/rides/manufacturers/create/') {
this.handleResponse(event);
}
});
},
async submitForm(event) {
if (this.submitting) return;
this.submitting = true;
const formData = new FormData(event.target);
const csrfToken = this.$el.querySelector('[name=csrfmiddlewaretoken]').value;
// Use HTMX for form submission
htmx.ajax('POST', '/rides/manufacturers/create/', { htmx.ajax('POST', '/rides/manufacturers/create/', {
values: Object.fromEntries(formData), values: Object.fromEntries(formData),
headers: { headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value 'X-CSRFToken': csrfToken
} },
target: this.$el,
swap: 'none'
}); });
},
// Handle HTMX response using event listeners handleResponse(event) {
document.addEventListener('htmx:afterRequest', function handleResponse(event) { this.submitting = false;
if (event.detail.pathInfo.requestPath === '/rides/manufacturers/create/') {
document.removeEventListener('htmx:afterRequest', handleResponse);
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) { if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) {
const data = JSON.parse(event.detail.xhr.response); const data = JSON.parse(event.detail.xhr.response);
if (typeof selectManufacturer === 'function') {
selectManufacturer(data.id, data.name); // Dispatch event with manufacturer data for parent components
} this.$dispatch('manufacturer-created', {
$dispatch('close-manufacturer-modal'); id: data.id,
} name: data.name
submitting = false; });
}
}); // Close modal if in modal context
}"> this.$dispatch('close-manufacturer-modal');
} else {
// Handle error case
this.$dispatch('manufacturer-creation-error', {
error: event.detail.xhr.responseText
});
}
}
}));
});
</script>
<form method="post"
class="space-y-6"
x-data="manufacturerForm()"
@submit.prevent="submitForm($event)">
{% csrf_token %} {% csrf_token %}
<div id="manufacturer-form-notification"></div> <div id="manufacturer-form-notification"></div>

View File

@@ -1,53 +1,103 @@
{% load static %} {% load static %}
<form method="post" <script>
class="space-y-6" document.addEventListener('alpine:init', () => {
x-data="{ Alpine.data('rideModelForm', () => ({
submitting: false, submitting: false,
manufacturerSearchTerm: '', manufacturerSearchTerm: '',
setManufacturerModal(value, term = '') {
const parentForm = document.querySelector('[x-data]'); init() {
if (parentForm) { // Listen for HTMX events on this form
const parentData = Alpine.$data(parentForm); this.$el.addEventListener('htmx:afterRequest', (event) => {
if (parentData && parentData.setManufacturerModal) { if (event.detail.pathInfo.requestPath === '/rides/models/create/') {
parentData.setManufacturerModal(value, term); this.handleResponse(event);
} }
} });
}
}" // Initialize form with any pre-filled values
@submit.prevent=" this.initializeForm();
if (!submitting) { },
submitting = true;
const formData = new FormData($event.target); initializeForm() {
const searchInput = this.$el.querySelector('#id_ride_model_search');
const nameInput = this.$el.querySelector('#id_name');
if (searchInput && searchInput.value && nameInput) {
nameInput.value = searchInput.value;
}
},
setManufacturerModal(value, term = '') {
// Dispatch event to parent component to handle manufacturer modal
this.$dispatch('set-manufacturer-modal', {
show: value,
searchTerm: term
});
},
async submitForm(event) {
if (this.submitting) return;
this.submitting = true;
const formData = new FormData(event.target);
const csrfToken = this.$el.querySelector('[name=csrfmiddlewaretoken]').value;
// Use HTMX for form submission
htmx.ajax('POST', '/rides/models/create/', { htmx.ajax('POST', '/rides/models/create/', {
values: Object.fromEntries(formData), values: Object.fromEntries(formData),
headers: { headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value 'X-CSRFToken': csrfToken
} },
target: this.$el,
swap: 'none'
}); });
},
// Handle HTMX response using event listeners handleResponse(event) {
document.addEventListener('htmx:afterRequest', function handleResponse(event) { this.submitting = false;
if (event.detail.pathInfo.requestPath === '/rides/models/create/') {
document.removeEventListener('htmx:afterRequest', handleResponse);
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) { if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) {
const data = JSON.parse(event.detail.xhr.response); const data = JSON.parse(event.detail.xhr.response);
if (typeof selectRideModel === 'function') {
selectRideModel(data.id, data.name); // Dispatch event with ride model data for parent components
} this.$dispatch('ride-model-created', {
const parentForm = document.querySelector('[x-data]'); id: data.id,
if (parentForm) { name: data.name
const parentData = Alpine.$data(parentForm); });
if (parentData && parentData.setRideModelModal) {
parentData.setRideModelModal(false); // Close modal if in modal context
} this.$dispatch('close-ride-model-modal');
} } else {
} // Handle error case
submitting = false; this.$dispatch('ride-model-creation-error', {
} error: event.detail.xhr.responseText
}); });
}"> }
},
selectManufacturer(manufacturerId, manufacturerName) {
// Update manufacturer fields using AlpineJS reactive approach
const manufacturerInput = this.$el.querySelector('#id_manufacturer');
const searchInput = this.$el.querySelector('#id_manufacturer_search');
const resultsDiv = this.$el.querySelector('#manufacturer-search-results');
if (manufacturerInput) manufacturerInput.value = manufacturerId;
if (searchInput) searchInput.value = manufacturerName;
if (resultsDiv) resultsDiv.innerHTML = '';
},
clearManufacturerResults() {
const resultsDiv = this.$el.querySelector('#manufacturer-search-results');
if (resultsDiv) resultsDiv.innerHTML = '';
}
}));
});
</script>
<form method="post"
class="space-y-6"
x-data="rideModelForm()"
@submit.prevent="submitForm($event)"
@click.outside="clearManufacturerResults()">
{% csrf_token %} {% csrf_token %}
<div id="ride-model-notification"></div> <div id="ride-model-notification"></div>