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'
}); });
},
handleResponse(event) {
this.submitting = false;
// Handle HTMX response using event listeners if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) {
document.addEventListener('htmx:afterRequest', function handleResponse(event) { const data = JSON.parse(event.detail.xhr.response);
if (event.detail.pathInfo.requestPath === '/rides/designers/create/') {
document.removeEventListener('htmx:afterRequest', handleResponse); // Dispatch event with designer data for parent components
this.$dispatch('designer-created', {
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) { id: data.id,
const data = JSON.parse(event.detail.xhr.response); name: data.name
if (typeof selectDesigner === 'function') { });
selectDesigner(data.id, data.name);
} // Close modal if in modal context
$dispatch('close-designer-modal'); this.$dispatch('close-designer-modal');
} } else {
submitting = false; // 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'
}); });
},
handleResponse(event) {
this.submitting = false;
// Handle HTMX response using event listeners if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) {
document.addEventListener('htmx:afterRequest', function handleResponse(event) { const data = JSON.parse(event.detail.xhr.response);
if (event.detail.pathInfo.requestPath === '/rides/manufacturers/create/') {
document.removeEventListener('htmx:afterRequest', handleResponse); // Dispatch event with manufacturer data for parent components
this.$dispatch('manufacturer-created', {
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) { id: data.id,
const data = JSON.parse(event.detail.xhr.response); name: data.name
if (typeof selectManufacturer === 'function') { });
selectManufacturer(data.id, data.name);
} // Close modal if in modal context
$dispatch('close-manufacturer-modal'); this.$dispatch('close-manufacturer-modal');
} } else {
submitting = false; // 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);
}
}
}
}"
@submit.prevent="
if (!submitting) {
submitting = true;
const formData = new FormData($event.target);
htmx.ajax('POST', '/rides/models/create/', {
values: Object.fromEntries(formData),
headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
} }
}); });
// Handle HTMX response using event listeners // Initialize form with any pre-filled values
document.addEventListener('htmx:afterRequest', function handleResponse(event) { this.initializeForm();
if (event.detail.pathInfo.requestPath === '/rides/models/create/') { },
document.removeEventListener('htmx:afterRequest', handleResponse);
initializeForm() {
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) { const searchInput = this.$el.querySelector('#id_ride_model_search');
const data = JSON.parse(event.detail.xhr.response); const nameInput = this.$el.querySelector('#id_name');
if (typeof selectRideModel === 'function') { if (searchInput && searchInput.value && nameInput) {
selectRideModel(data.id, data.name); nameInput.value = searchInput.value;
} }
const parentForm = document.querySelector('[x-data]'); },
if (parentForm) {
const parentData = Alpine.$data(parentForm); setManufacturerModal(value, term = '') {
if (parentData && parentData.setRideModelModal) { // Dispatch event to parent component to handle manufacturer modal
parentData.setRideModelModal(false); this.$dispatch('set-manufacturer-modal', {
} show: value,
} searchTerm: term
}
submitting = false;
}
}); });
}"> },
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/', {
values: Object.fromEntries(formData),
headers: {
'X-CSRFToken': csrfToken
},
target: this.$el,
swap: 'none'
});
},
handleResponse(event) {
this.submitting = false;
if (event.detail.xhr.status >= 200 && event.detail.xhr.status < 300) {
const data = JSON.parse(event.detail.xhr.response);
// Dispatch event with ride model data for parent components
this.$dispatch('ride-model-created', {
id: data.id,
name: data.name
});
// Close modal if in modal context
this.$dispatch('close-ride-model-modal');
} else {
// Handle error case
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>