{"action":"created","issue":{"url":"https://api.github.com/repos/erikras/redux-form/issues/1562","repository_url":"https://api.github.com/repos/erikras/redux-form","labels_url":"https://api.github.com/repos/erikras/redux-form/issues/1562/labels{/name}","comments_url":"https://api.github.com/repos/erikras/redux-form/issues/1562/comments","events_url":"https://api.github.com/repos/erikras/redux-form/issues/1562/events","html_url":"https://github.com/erikras/redux-form/issues/1562","id":171866894,"number":1562,"title":"Poll: Flatten Validation Errors?","user":{"login":"erikras","id":4396759,"avatar_url":"https://avatars.githubusercontent.com/u/4396759?v=3","gravatar_id":"","url":"https://api.github.com/users/erikras","html_url":"https://github.com/erikras","followers_url":"https://api.github.com/users/erikras/followers","following_url":"https://api.github.com/users/erikras/following{/other_user}","gists_url":"https://api.github.com/users/erikras/gists{/gist_id}","starred_url":"https://api.github.com/users/erikras/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erikras/subscriptions","organizations_url":"https://api.github.com/users/erikras/orgs","repos_url":"https://api.github.com/users/erikras/repos","events_url":"https://api.github.com/users/erikras/events{/privacy}","received_events_url":"https://api.github.com/users/erikras/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/erikras/redux-form/labels/%3C-------%20READ%20THIS","name":"<------- READ THIS","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":11,"created_at":"2016-08-18T10:17:01Z","updated_at":"2016-08-18T14:42:06Z","closed_at":null,"body":"This idea came from @clayne11's excellent write-up on #1310.\r\n\r\n---\r\nThere are a few problems with the current way that validation errors are returned:\r\n\r\n1. Array errors (`_error`) don't work with `ImmutableJS`\r\n2. Using `_error` for object and array errors is just gross.\r\n\r\nWhat if we flattened the error object down to a map from field name to error?\r\n\r\n### Deep\r\nThis is the way we currently return errors:\r\n```javascript\r\nconst errors = {\r\n  test: {\r\n    _error: 'Awkward special rule'\r\n    foo: 'This is an error',\r\n    bar: 'This is another error',\r\n  },\r\n  foobar: 'An error',\r\n  anArrayField: [\r\n    {\r\n      test: 'This is not a valid value'\r\n    }\r\n  ]\r\n  _error: 'This is a form wide error'\r\n}\r\nerrors.anArrayField._error = 'Must have 3 entries'\r\n```\r\n\r\n### Flattened\r\nThis is the proposed new way:\r\n```javascript\r\nconst errors = {\r\n  test: 'No longer awkward',\r\n  'test.foo': 'This is an error',\r\n  'test.bar': 'This is another error',\r\n  foobar: 'An error',\r\n  anArrayField: 'Must have 3 entries' \r\n  'anArrayField[0].test': 'This is not a valid value',\r\n  _error: 'This is a form wide error' // still needed :-(\r\n}\r\n```\r\nThis makes it trivial to represent errors at any depth in the form tree without having to rely on the magical `_error` property.\r\n\r\n# Poll Question\r\n\r\n### Should we migrate to a flattened error structure for the `v6.0.0` release?\r\n---\r\nPlease vote with the 👍 buttons. And feel free to give reasons in the comments.\r\n"},"comment":{"url":"https://api.github.com/repos/erikras/redux-form/issues/comments/240744585","html_url":"https://github.com/erikras/redux-form/issues/1562#issuecomment-240744585","issue_url":"https://api.github.com/repos/erikras/redux-form/issues/1562","id":240744585,"user":{"login":"smirea","id":544097,"avatar_url":"https://avatars.githubusercontent.com/u/544097?v=3","gravatar_id":"","url":"https://api.github.com/users/smirea","html_url":"https://github.com/smirea","followers_url":"https://api.github.com/users/smirea/followers","following_url":"https://api.github.com/users/smirea/following{/other_user}","gists_url":"https://api.github.com/users/smirea/gists{/gist_id}","starred_url":"https://api.github.com/users/smirea/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smirea/subscriptions","organizations_url":"https://api.github.com/users/smirea/orgs","repos_url":"https://api.github.com/users/smirea/repos","events_url":"https://api.github.com/users/smirea/events{/privacy}","received_events_url":"https://api.github.com/users/smirea/received_events","type":"User","site_admin":false},"created_at":"2016-08-18T14:42:06Z","updated_at":"2016-08-18T14:42:06Z","body":"I would personally prefer the deep format as I find it much easier to work with and rationalize about an error result that has the same structure as my input (or as similar as possible)\r\n\r\nHow about an alternative error format that has a set structure? Example returning an object with `{$error: *, $values: *}` should pass the `$error`to the validation parent and continue traversing on the `$values`\r\n\r\nExample given the following structure:\r\n\r\n```js\r\n{\r\n    name: String,\r\n    price: Number,\r\n    stores: [{\r\n        city: String,\r\n        zip: Number\r\n    }]\r\n}\r\n```\r\n\r\nThe validation method could look very similar to the input:\r\n\r\n```js\r\nconst validate = ({name, price, stores}) => ({\r\n    name: name ? null : 'Name is required',\r\n    price: isNumeric(price) ? null : 'Invalid Price',\r\n    stores: {\r\n        $error: stores.some(obj => !!validateStore(obj)) ? 'Invalid stores, check the field errors' : null,\r\n        $values: stores.map(validateStore),\r\n    },\r\n});\r\n\r\nconst validateStore = ({city, zip}) => ({\r\n    city: city === ('' + city).toUpperCase() ? null : 'CITY MUST BE UPPERCASE',\r\n});\r\n\r\nconst isNumeric = num => !Number.isNaN(parseFloat(price));\r\n```\r\n\r\nThe format can easily be improved with a helper function that returns the error only if one of the children is invalid (though implementing this could be an exercise to the user)\r\n\r\n```js\r\nconst validateArray = (arrayError, arr, validateValue) => {\r\n    const result = arr.map(validateValue);\r\n    const hasError = result.some(obj => obj && Object.keys(obj).some(key => !!obj[key]));\r\n    return !hasError ? null : {\r\n        $error: arrayError,\r\n        $values: result,\r\n    };\r\n}\r\n```\r\n\r\nUsing the above would result in the entire validation looking like:\r\n\r\n```\r\nconst validate = ({name, price, stores}) => ({\r\n    name: name ? null : 'Name is required',\r\n    price: isNumeric(price) ? null : 'Invalid Price',\r\n    stores: validateArray('Invalid stores, check the field errors', stores, validateStore),\r\n});\r\n\r\nconst validateStore = ({city, zip}) => ({\r\n    city: city === ('' + city).toUpperCase() ? null : 'CITY MUST BE UPPERCASE',\r\n});\r\n\r\nconst isNumeric = num => !Number.isNaN(parseFloat(price));\r\n```"}}
{"actor":{"display_login":"smirea"}}