diff --git a/InvenTree/templates/js/translated/forms.js b/InvenTree/templates/js/translated/forms.js
index c303c55d17..2fc650e0e6 100644
--- a/InvenTree/templates/js/translated/forms.js
+++ b/InvenTree/templates/js/translated/forms.js
@@ -864,6 +864,78 @@ function clearFormErrors(options) {
$(options.modal).find('#non-field-errors').html('');
}
+/*
+ * Display form error messages as returned from the server,
+ * specifically for errors returned in an array.
+ *
+ * We need to know the unique ID of each item in the array,
+ * and the array length must equal the length of the array returned from the server
+ *
+ * arguments:
+ * - response: The JSON error response from the server
+ * - parent: The name of the parent field e.g. "items"
+ * - options: The global options struct
+ *
+ * options:
+ * - nested: A map of nested ID values for the "parent" field
+ * e.g.
+ * {
+ * "items": [
+ * 1,
+ * 2,
+ * 12
+ * ]
+ * }
+ *
+ */
+
+function handleNestedErrors(errors, field_name, options) {
+
+ var error_list = errors[field_name];
+
+ // Ignore null or empty list
+ if (!error_list) {
+ return;
+ }
+
+ var nest_list = nest_list = options["nested"][field_name];
+
+ // Nest list must be provided!
+ if (!nest_list) {
+ console.log(`WARNING: handleNestedErrors missing nesting options for field '${fieldName}'`);
+ return;
+ }
+
+ for (var idx = 0; idx < error_list.length; idx++) {
+
+ var error_item = error_list[idx];
+
+ if (idx >= nest_list.length) {
+ console.log(`WARNING: handleNestedErrors returned greater number of errors (${error_list.length}) than could be handled (${nest_list.length})`);
+ break;
+ }
+
+ // Extract the particular ID of the nested item
+ var nest_id = nest_list[idx];
+
+ // Here, error_item is a map of field names to error messages
+ for (sub_field_name in error_item) {
+ var errors = error_item[sub_field_name];
+
+ // Find the target (nested) field
+ var target = `${field_name}_${sub_field_name}_${nest_id}`;
+
+ for (var ii = errors.length-1; ii >= 0; ii--) {
+
+ var error_text = errors[ii];
+
+ addFieldErrorMessage(target, error_text, ii, options);
+ }
+ }
+ }
+}
+
+
/*
* Display form error messages as returned from the server.
@@ -913,28 +985,30 @@ function handleFormErrors(errors, fields, options) {
for (var field_name in errors) {
- // Add the 'has-error' class
- $(options.modal).find(`#div_id_${field_name}`).addClass('has-error');
+ if (field_name in fields) {
- var field_dom = $(options.modal).find(`#errors-${field_name}`); // $(options.modal).find(`#id_${field_name}`);
+ var field = fields[field_name];
- var field_errors = errors[field_name];
+ if ((field.type == "field") && ("child" in field)) {
+ // This is a "nested" field
+ handleNestedErrors(errors, field_name, options);
+ } else {
+ // This is a "simple" field
- if (field_errors && !first_error_field && isFieldVisible(field_name, options)) {
- first_error_field = field_name;
- }
+ var field_errors = errors[field_name];
- // Add an entry for each returned error message
- for (var ii = field_errors.length-1; ii >= 0; ii--) {
+ if (field_errors && !first_error_field && isFieldVisible(field_name, options)) {
+ first_error_field = field_name;
+ }
- var error_text = field_errors[ii];
+ // Add an entry for each returned error message
+ for (var ii = field_errors.length-1; ii >= 0; ii--) {
- var error_html = `
-
- ${error_text}
- `;
+ var error_text = field_errors[ii];
- field_dom.append(error_html);
+ addFieldErrorMessage(field_name, error_text, ii, options);
+ }
+ }
}
}
@@ -952,6 +1026,30 @@ function handleFormErrors(errors, fields, options) {
}
+/*
+ * Add a rendered error message to the provided field
+ */
+function addFieldErrorMessage(field_name, error_text, error_idx, options) {
+
+ // Add the 'has-error' class
+ $(options.modal).find(`#div_id_${field_name}`).addClass('has-error');
+
+ var field_dom = $(options.modal).find(`#errors-${field_name}`);
+
+ if (field_dom) {
+
+ var error_html = `
+
+ ${error_text}
+ `;
+
+ field_dom.append(error_html);
+ } else {
+ console.log(`WARNING: addFieldErrorMessage could not locate field '${field_name}`);
+ }
+}
+
+
function isFieldVisible(field, options) {
return $(options.modal).find(`#div_id_${field}`).is(':visible');