From f979d6a864df92d22e376432e7bbdbc586e2aee6 Mon Sep 17 00:00:00 2001 From: BrainFooLong Date: Mon, 27 Sep 2021 18:13:56 +0200 Subject: [PATCH] changed output of option `flatList`, it now contains an array list with same values like native `FormData()` updated testcases to reflect new behaviour change --- CHANGELOG.md | 3 +- README.md | 20 ++- dist/form-data-json.js | 205 ++++++++++++++++++++--------- dist/form-data-json.min.js | 4 +- docs/scripts/form-data-json.js | 205 ++++++++++++++++++++--------- docs/scripts/form-data-json.min.js | 4 +- docs/tests/test.html | 189 +++++++++++++------------- package.json | 2 +- src/form-data-json.js | 152 ++++++++++++++------- 9 files changed, 507 insertions(+), 277 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a490fc..5617313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * fixed https://github.com/brainfoolong/form-data-json/issues/13 in `toJson()` * changed option `uncheckedValue` is now false by default, instead of undefined * added option `resetOthers` for `fromJson()` +* changed output of option `flatList`, it now contains an array list with same values like native `FormData()` ### 2.0.2beta - 27.09.2021 * incorrectly compiled files @@ -12,7 +13,7 @@ ### 2.0.0beta - 26.09.2021 * complete refactoring * removed class `FormDataJsonOptions`. Use bare `{}` objects now as options -* removed method `FormDataJson.flattenJsonFormValues`. Use `flatList = true` option in `toJson` +* removed method `FormDataJson.flattenJsonFormValues`. Use `flatList = true` option in `toJson`. Note: Output still has changed significantly to v1. * removed method `FormDataJson.setInputValue`. No direct replacement. Use `fromJson` if you need to set any input value * removed 3rd parameter `formToJson/toJson` callback function. It is now set into option `filesCallback` * renamed method `formToJson` to `toJson` diff --git a/README.md b/README.md index e097765..bc84c12 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ You can edit this defaults globally by modifying `FormDataJson.defaultOptionsToJ * If undefined, than the unchecked field will be ignored in output * @type {*} */ -'uncheckedValue': undefined, +'uncheckedValue': false, /** * A function, where first parameter is the input field to check for, that must return true if the field should be included @@ -113,22 +113,25 @@ You can edit this defaults globally by modifying `FormDataJson.defaultOptionsToJ 'inputFilter': null, /** - * Does return a flat key/value list of values instead of multiple dimensions - * This will use the original input names as key, doesn't matter how weird they are - * Exepected keys are similar to FormData() keys + * Does return an array list, with same values as native Array.from(new FormData(form)) + * So a list entry will look like [["inputName", "inputValue"], ["inputName", "inputValue"]] + * The input name will not be changed and the list can contain multiple equal names * @type {boolean} */ 'flatList': false, /** * If true, than this does skip empty fields from the output + * Empty is considered to be: an empty array (for multiple selects/checkboxes) and an empty input field (length = 0) + * This does recursively remove keys + * Example: {"agb":"1", "user" : [{"name" : ""},{"name" : ""}]} will be {"agb":"1"} * @type {boolean} */ 'skipEmpty': false, /** * A function the will be called when all file fields are read as base64 data uri - * Note: This does modify the returned object from the original call of toJson() afterwards + * Note: If this is given, than the original return value from toJson() is null and the values are passed to this callback as first parameter * @type {function|null} */ 'filesCallback': null, @@ -160,6 +163,13 @@ You can edit this defaults globally by modifying `FormDataJson.defaultOptionsFro */ 'clearOthers': false, +/** + * If true, than all fields that are not exist in the passed values object, will be reset + * Not exist means, the value must be undefined + * @type {boolean} + */ +'resetOthers': false, + /** * If true, when a fields value has changed, a "change" event will be fired * @type {boolean} diff --git a/dist/form-data-json.js b/dist/form-data-json.js index 899986c..608ee47 100644 --- a/dist/form-data-json.js +++ b/dist/form-data-json.js @@ -1,5 +1,5 @@ 'use strict'; -// form-data-json-convert | version: 2.0.2beta | url: https://github.com/brainfoolong/form-data-json +// form-data-json-convert | version: 2.0.3beta | url: https://github.com/brainfoolong/form-data-json /** * Form Data Json Converter @@ -34,7 +34,7 @@ var FormDataJson = /*#__PURE__*/function () { * Get values from all form elements inside the given element * @param {*} el * @param {Object=} options - * @return {Object} + * @return {Object|Array} */ FormDataJson.toJson = function toJson(el, options) { options = FormDataJson.merge(FormDataJson.defaultOptionsToJson, options); @@ -70,7 +70,7 @@ var FormDataJson = /*#__PURE__*/function () { } var tree = FormDataJson.getFieldTree(el, isValidInput); - var returnObject = {}; + var returnObject = options.flatList ? [] : {}; var files = []; /** * Recursive get values @@ -144,14 +144,99 @@ var FormDataJson = /*#__PURE__*/function () { } } else { value = input.value; + } - if (options.skipEmpty && FormDataJson.stringify(value) === '') { - continue; + if (options.flatList) { + values.push([row.name, value]); + } else { + values[objectKey] = value; + } + } + } + /** + * Does some final cleanup before output data + * @return {*} + */ + + /** + * Make an object to array if possible + * @param {Object} object + * @return {*} + * @private + */ + + + function arrayfy(object) { + if (FormDataJson.isObject(object)) { + var count = 0; + var valid = true; + + for (var key in object) { + if (FormDataJson.isObject(object[key]) && !(object[key] instanceof Element)) { + object[key] = arrayfy(object[key]); + } + + if (parseInt(key) !== count) { + valid = false; } + + count++; + } + + if (valid) { + var arr = []; + + for (var i in object) { + arr.push(object[i]); + } + + return arr; + } + } + + return object; + } + /** + * Does some final cleanup before output data + * @return {*} + */ + + + function output() { + returnObject = arrayfy(returnObject); + if (options.skipEmpty) returnObject = removeEmpty(returnObject) || {}; + return returnObject; + } + /** + * Recursively remove empty keys + * @param {Object} object + */ + + + function removeEmpty(object) { + var isArray = FormDataJson.isArray(object); + var newObject = isArray ? [] : {}; + var count = 0; + + for (var key in object) { + if (FormDataJson.isObject(object[key]) || FormDataJson.isArray(object[key])) { + object[key] = removeEmpty(object[key]) || ''; + } + + if (typeof object[key] !== 'object' && FormDataJson.stringify(object[key]) === '') { + continue; } - values[objectKey] = value; + if (isArray) { + newObject.push(object[key]); + } else { + newObject[key] = object[key]; + } + + count++; } + + return count ? newObject : null; } recursion(tree, returnObject); @@ -184,7 +269,7 @@ var FormDataJson = /*#__PURE__*/function () { filesDone++; if (filesDone === filesRequired) { - options.filesCallback(FormDataJson.arrayfy(returnObject)); + options.filesCallback(output()); } }; @@ -201,28 +286,34 @@ var FormDataJson = /*#__PURE__*/function () { } })(); } else if (options.filesCallback) { - options.filesCallback(FormDataJson.arrayfy(returnObject)); + options.filesCallback(output()); + return null; } - return FormDataJson.arrayfy(returnObject); + return output(); } /** * Fill given form values into all form elements inside given element * @param {*} el - * @param {Object} values + * @param {Object|Array} values * @param {Object=} options * @param {string=} keyPrefix Internal only */ ; FormDataJson.fromJson = function fromJson(el, values, options, keyPrefix) { - if (!FormDataJson.isObject(values)) return; + if (!FormDataJson.isObject(values) && !FormDataJson.isArray(values)) return; options = FormDataJson.merge(FormDataJson.defaultOptionsFromJson, options); var tree = FormDataJson.getFieldTree(el); + var lastUsedFlatListIndex = {}; if (options.clearOthers) { FormDataJson.clear(el); } + + if (options.resetOthers) { + FormDataJson.reset(el); + } /** * Recursive set values * @param {*} inputs @@ -243,10 +334,27 @@ var FormDataJson = /*#__PURE__*/function () { } continue; - } // skip fields that are not presented in the + } // flat list must search correct entry for given input name + + + if (options.flatList) { + for (var i in newValues) { + var value = newValues[i]; + + if (value && value[0] === row.name) { + if (lastUsedFlatListIndex[row.name] !== i) { + lastUsedFlatListIndex[row.name] = i; + FormDataJson.setInputValue(row, value[1], options.triggerChangeEvent); + break; + } + } + } + + continue; + } // skip fields that are not presented in the value list - if (!options.clearOthers && typeof newValues[objectKey] === 'undefined') { + if (typeof newValues[objectKey] === 'undefined') { continue; } @@ -348,44 +456,6 @@ var FormDataJson = /*#__PURE__*/function () { recursion(tree); } - /** - * Make an object to array if possible - * @param {Object} object - * @return {*} - * @private - */ - ; - - FormDataJson.arrayfy = function arrayfy(object) { - if (FormDataJson.isObject(object)) { - var count = 0; - var valid = true; - - for (var key in object) { - if (FormDataJson.isObject(object[key]) && !(object[key] instanceof Element)) { - object[key] = FormDataJson.arrayfy(object[key]); - } - - if (parseInt(key) !== count) { - valid = false; - } - - count++; - } - - if (valid) { - var arr = []; - - for (var i in object) { - arr.push(object[i]); - } - - return arr; - } - } - - return object; - } /** * Set input value * @param {*} row @@ -542,17 +612,18 @@ var FormDataJson = /*#__PURE__*/function () { for (var j = 0; j < keyPartsLength; j++) { var keyPart = keyParts[j]; - currentName = currentName ? currentName + '[' + keyPart + ']' : keyPart; // auto increment key part + var newCurrentName = currentName ? currentName + '[' + keyPart + ']' : keyPart; // auto increment key part if (keyPart === '') { - if (typeof autoIncrementCounts[currentName] === 'undefined') { - autoIncrementCounts[currentName] = 0; + if (typeof autoIncrementCounts[newCurrentName] === 'undefined') { + autoIncrementCounts[newCurrentName] = 0; } - keyPart = autoIncrementCounts[currentName].toString(); - autoIncrementCounts[currentName]++; - } // last level + keyPart = autoIncrementCounts[newCurrentName].toString(); + autoIncrementCounts[newCurrentName]++; + } + currentName = currentName ? currentName + '[' + keyPart + ']' : keyPart; // last level if (keyPartsLength - 1 === j) { // radio elements are special @@ -674,7 +745,7 @@ FormDataJson.defaultOptionsToJson = { * If undefined, than the unchecked field will be ignored in output * @type {*} */ - 'uncheckedValue': undefined, + 'uncheckedValue': false, /** * A function, where first parameter is the input field to check for, that must return true if the field should be included @@ -684,22 +755,25 @@ FormDataJson.defaultOptionsToJson = { 'inputFilter': null, /** - * Does return a flat key/value list of values instead of multiple dimensions - * This will use the original input names as key, doesn't matter how weird they are - * Exepected keys are similar to FormData() keys + * Does return an array list, with same values as native Array.from(new FormData(form)) + * So a list entry will look like [["inputName", "inputValue"], ["inputName", "inputValue"]] + * The input name will not be changed and the list can contain multiple equal names * @type {boolean} */ 'flatList': false, /** * If true, than this does skip empty fields from the output + * Empty is considered to be: an empty array (for multiple selects/checkboxes) and an empty input field (length = 0) + * This does recursively remove keys + * Example: {"agb":"1", "user" : [{"name" : ""},{"name" : ""}]} will be {"agb":"1"} * @type {boolean} */ 'skipEmpty': false, /** * A function the will be called when all file fields are read as base64 data uri - * Note: This does modify the returned object from the original call of toJson() afterwards + * Note: If this is given, than the original return value from toJson() is null and the values are passed to this callback as first parameter * @type {function|null} */ 'filesCallback': null, @@ -726,6 +800,13 @@ FormDataJson.defaultOptionsFromJson = { */ 'clearOthers': false, + /** + * If true, than all fields that are not exist in the passed values object, will be reset + * Not exist means, the value must be undefined + * @type {boolean} + */ + 'resetOthers': false, + /** * If true, when a fields value has changed, a "change" event will be fired * @type {boolean} diff --git a/dist/form-data-json.min.js b/dist/form-data-json.min.js index c91e1f1..40bdd69 100644 --- a/dist/form-data-json.min.js +++ b/dist/form-data-json.min.js @@ -1,3 +1,3 @@ 'use strict'; -// form-data-json-convert | version: 2.0.2beta | url: https://github.com/brainfoolong/form-data-json -var FormDataJson=function(){function a(){}return a.toJson=function toJson(b,c){function d(b){if("function"==typeof c.inputFilter&&!0!==c.inputFilter(b))return!1;if(!c.includeDisabled&&b.disabled)return!1;var d=(b.type||"text").toLowerCase();return!(!c.includeButtonValues&&(b instanceof HTMLButtonElement||-1 Test FormDataJson -