From a9d5b776d378e9b2d372e77befca2d66d07ffc0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 4 Oct 2021 22:41:59 +1100 Subject: [PATCH] Adds error handling of nested form fields in the API form processing layer - Muy complejo - But the results speak for themselves! -This will need to be rolled out into the coming refactor... --- InvenTree/templates/js/translated/forms.js | 128 ++++++++++++++++++--- 1 file changed, 113 insertions(+), 15 deletions(-) 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');