Address form: Reduce useless XHR calls

This commit is contained in:
Raphael Michel
2025-08-20 12:43:21 +02:00
committed by GitHub
parent 32be6a159e
commit 500bca1323

View File

@@ -1,6 +1,10 @@
$(function () { $(function () {
"use strict"; "use strict";
// Responses are expected to only depend on the GET parameters passed, so we can have a little client-side cache
// to prevent fetching the same thing many times.
var responseCache = {};
$("[data-address-information-url]").each(function () { $("[data-address-information-url]").each(function () {
let xhr; let xhr;
const form = $(this); const form = $(this);
@@ -21,31 +25,12 @@ $(function () {
dependents[$(this).attr("name").split("-").pop()] = $(this) dependents[$(this).attr("name").split("-").pop()] = $(this)
}) })
const update = function (ev) { if (!Object.values(dependents).some((el) => el.length)) {
if (xhr) { // No address fields found, do not create request
xhr.abort(); return;
} }
dependents.state.prop("data-selected-value", dependents.state.val()); const update_form = function (data) {
if (dependents.transmission_type) {
dependents.transmission_type.prop("data-selected-value", dependents.transmission_type.val());
}
for (var k in dependents) dependents[k].prop("disabled", true);
loader.show();
var url = new URL(baseUrl, location.href);
// Address depends on all annotated fields
form.find("[data-trigger-address-info]").each(function () {
// Remove prefix of the form to get actual field name
if (($(this).attr("type") === "radio" || $(this).attr("type") === "checkbox") && !$(this).prop("checked")) {
return
}
url.searchParams.append($(this).attr("name").split("-").pop(), $(this).val());
})
if (dependents.transmission_type) {
url.searchParams.append("transmission_type_required", !dependents.transmission_type.find("option[value='-']").length);
}
xhr = $.getJSON(url, function (data) {
var selected_state = dependents.state.prop("data-selected-value"); var selected_state = dependents.state.prop("data-selected-value");
if (selected_state) dependents.state.prop("data-selected-value", ""); if (selected_state) dependents.state.prop("data-selected-value", "");
dependents.state.find("option:not([value=''])").remove(); dependents.state.find("option:not([value=''])").remove();
@@ -106,18 +91,63 @@ $(function () {
} }
} }
for (var k in dependents) dependents[k].prop("disabled", false); for (var k in dependents) dependents[k].prop("disabled", false);
}).always(function() {
loader.hide(); loader.hide();
}
const update = function (ev) {
if (xhr) {
xhr.abort();
}
dependents.state.prop("data-selected-value", dependents.state.val());
if (dependents.transmission_type) {
dependents.transmission_type.prop("data-selected-value", dependents.transmission_type.val());
}
for (var k in dependents) dependents[k].prop("disabled", true);
loader.show();
var url = new URL(baseUrl, location.href);
// Address depends on all annotated fields
form.find("[data-trigger-address-info]").each(function () {
// Remove prefix of the form to get actual field name
if (($(this).attr("type") === "radio" || $(this).attr("type") === "checkbox") && !$(this).prop("checked")) {
return
}
url.searchParams.append($(this).attr("name").split("-").pop(), $(this).val());
})
if (dependents.transmission_type) {
url.searchParams.append("transmission_type_required", !dependents.transmission_type.find("option[value='-']").length);
}
if (!(url in responseCache)) {
responseCache[url] = new Promise((resolve, reject) => {
xhr = $.ajax({
dataType: "json",
url: url,
timeout: 3000,
success: resolve,
}).fail(function(){ }).fail(function(){
reject();
});
})
}
Promise.resolve(responseCache[url]).then(function (data) {
responseCache[url] = data;
update_form(data);
}).catch(function () {
delete responseCache[url];
// In case of errors, show everything and require nothing, we can still handle errors in backend // In case of errors, show everything and require nothing, we can still handle errors in backend
for(var k in dependents) { for (var k in dependents) {
const dependent = dependents[k], const dependent = dependents[k],
visible = true, visible = true,
required = false; required = false;
dependent.closest(".form-group").toggle(visible).toggleClass('required', required); dependent.closest(".form-group").toggle(visible).toggleClass('required', required);
dependent.prop("required", required); dependent.prop("required", required).prop("disabled", false);
} }
}).finally(function () {
loader.hide();
}); });
}; };
update(); update();