mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 09:11:08 -05:00
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:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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: '',
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// Listen for HTMX events on this form
|
||||||
|
this.$el.addEventListener('htmx:afterRequest', (event) => {
|
||||||
|
if (event.detail.pathInfo.requestPath === '/rides/models/create/') {
|
||||||
|
this.handleResponse(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize form with any pre-filled values
|
||||||
|
this.initializeForm();
|
||||||
|
},
|
||||||
|
|
||||||
|
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 = '') {
|
setManufacturerModal(value, term = '') {
|
||||||
const parentForm = document.querySelector('[x-data]');
|
// Dispatch event to parent component to handle manufacturer modal
|
||||||
if (parentForm) {
|
this.$dispatch('set-manufacturer-modal', {
|
||||||
const parentData = Alpine.$data(parentForm);
|
show: value,
|
||||||
if (parentData && parentData.setManufacturerModal) {
|
searchTerm: term
|
||||||
parentData.setManufacturerModal(value, term);
|
});
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
async submitForm(event) {
|
||||||
}"
|
if (this.submitting) return;
|
||||||
@submit.prevent="
|
|
||||||
if (!submitting) {
|
this.submitting = true;
|
||||||
submitting = true;
|
const formData = new FormData(event.target);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
submitting = false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}">
|
|
||||||
|
// 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>
|
||||||
|
|||||||
Reference in New Issue
Block a user