├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json ├── src ├── core.js ├── handleError.js └── handleFetchError.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Sam Carré 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚨 Laravel VeeValidate 2 | ##### The super simple JS package that will handle your Laravel errors and automatically inject them into a VeeValidate instance ✨ 3 | 4 | ![Example Image](https://res.cloudinary.com/sammyjo20/image/upload/v1551134147/laravel-veevalidate/Example.png) 5 | 6 | ## Installation 7 | ``` 8 | npm i laravel-veevalidate 9 | ``` 10 | or 11 | ``` 12 | yarn add laravel-veevalidate 13 | ``` 14 | 15 | ## Usage 16 | Assuming you already have VeeValidate installed, you can use Laravel VeeValidate as a Vue Prototype. 17 | 18 | ```javascript 19 | import LaravelValidator from 'laravel-veevalidate'; 20 | 21 | Vue.prototype.$laravelValidator = LaravelValidator; 22 | ``` 23 | 24 | Alternatively, you can use it on a on a component-to-component basis. 25 | ```javascript 26 | import LaravelValidator from 'laravel-veevalidate'; 27 | ``` 28 | 29 | ### Using it from with Axios 30 | To use the error handler with Axios, you will need to place the handleError method inside of the catch() block of the Axios promise. 31 | 32 | The first parameter you must provide is the VeeValidate instance you would like to use. It's recommended to use the global directive ($validator). The second parameter is the response callback which Axios provides. 33 | ```javascript 34 | axios(...) 35 | .catch(error_response => { 36 | this.$laravelValidator.handleError(this.$validator, error_response) 37 | }) 38 | ``` 39 | 40 | ### Using it with Fetch 41 | To use the error handler with Fetch, you will need to place the handleFetchError method inside of the then() block of the Fetch promise. 42 | 43 | The first parameter you must provide is the VeeValidate instance you would like to use. It's recommended to use the global directive ($validator). The second parameter is the response callback which Fetch provides. 44 | 45 | ```javascript 46 | fetch(...) 47 | .then(response => { 48 | this.$laravelValidator.handleFetchError(this.$validator, response) 49 | }) 50 | ``` 51 | 52 | ### Clearing Errors 53 | **Important: Laravel VeeValidate does not clear your VeeValidate errors. Before your request you should clear the error bag from your VeeValidate Instance:** 54 | ```javascript 55 | // e.g: 56 | this.$validator.errors.clear(); 57 | ``` 58 | 59 | 60 | ### Custom field mapping 61 | Sometimes your Request/Eloquent attributes won't match your VeeValidate fields/names. You can really easily "map" this by passing a key value object as a third parameter. 62 | 63 | ```javascript 64 | // Axios 65 | this.$laravelValidator.handleError(this.$validator, error_response, { 66 | 'email_address': 'email address', // Attribute => Field Name 67 | }) 68 | }) 69 | 70 | // Fetch 71 | this.$laravelValidator.handleFetchError(this.$validator, response, { 72 | 'email_address': 'email address', // Attribute => Field Name 73 | }) 74 | }) 75 | ``` 76 | 77 | ### Options 78 | Laravel VeeValidate provides some simple options which you can pass as the **fourth** parameter of the handleError and handleFetchError methods. 79 | 80 | | Option | Description | Type | Default Value | Choices | 81 | | ------------- |-------------| :-----:| :-------------:|------------| 82 | | driver | Request driver you are using. | String | `axios` | `axios` `fetch` | 83 | | show_errors | Display console errors while in Development mode | Boolean | `true` | `true` `false` | 84 | 85 | #### Applying an option 86 | 87 | ```javascript 88 | this.$laravelValidator.handleError(this.$validator, error_response, {}, { 89 | show_errors: false 90 | }) 91 | ``` 92 | 93 | ## And that's it! ✨ 94 | This is my first JS/NPM package, I really hope it's been useful to you, if you like my work and want to show some love, consider buying me some coding fuel (Coffee) ❤ 95 | 96 | https://ko-fi.com/sammyjo20 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import handleError from './src/handleError.js'; 2 | import handleFetchError from './src/handleFetchError.js'; 3 | 4 | export default { 5 | handleError: handleError, 6 | handleFetchError: handleFetchError 7 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-veevalidate", 3 | "version": "1.3.1", 4 | "description": "The super simple JS package that'll translate your Laravel Validation errors into VeeValidate errors. ✨", 5 | "main": "index.js", 6 | "author": "Sammyjo20", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/Sammyjo20/laravel-veevalidate.git" 11 | }, 12 | "peerDependencies": { 13 | "vee-validate": "^2.0" 14 | }, 15 | "keywords": [ 16 | "Laravel", 17 | "VeeValidate", 18 | "Validation", 19 | "Validator" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if the given status is 422 (Unprocessable Entity) 3 | * 4 | * @param status 5 | * @returns {boolean} 6 | */ 7 | export function validStatus(status) { 8 | return status === 422; 9 | } 10 | 11 | /** 12 | * Display a warning 13 | * 14 | * @param message 15 | * @param display 16 | */ 17 | export function warning(message, display) { 18 | if (!message) { 19 | message = 'Unknown Warning'; 20 | } 21 | 22 | if (process.env.NODE_ENV && process.env.NODE_ENV === 'development' && display === true) { 23 | console.warn('[Laravel-VeeValidate Warning] ' + message); 24 | } 25 | } 26 | 27 | /** 28 | * Display a fatal error 29 | * 30 | * @param message 31 | * @param display 32 | */ 33 | export function fatalError(message, display) { 34 | if (!message) { 35 | message = 'Unknown Error'; 36 | } 37 | 38 | if (process.env.NODE_ENV && process.env.NODE_ENV === 'development' && display === true) { 39 | console.error('[Laravel-VeeValidate Fatal Error] ' + message); 40 | } 41 | } 42 | 43 | /** 44 | * Validate our field map 45 | * 46 | * @param field_map 47 | * @returns {boolean} 48 | */ 49 | export function validFieldMap(field_map) { 50 | let keys = Object.keys(field_map); 51 | let dup_keys = []; 52 | 53 | if (keys.length <= 0) { 54 | return false; 55 | } 56 | 57 | for(let i = 0; i < keys.length; i++) { 58 | let value = field_map[keys[i]]; 59 | 60 | if (!value) { 61 | return false; 62 | } 63 | 64 | if (dup_keys.includes(value)) { 65 | return false; 66 | } 67 | 68 | dup_keys.push(keys[i]); 69 | } 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * Check if the response has any errors. 76 | * 77 | * @param data 78 | * @returns {boolean} 79 | */ 80 | export function responseHasErrors(data) { 81 | if (!data || data.length <= 0) { 82 | return false; 83 | } 84 | 85 | if (!data.errors || data.errors.length <= 0) { 86 | return false; 87 | } 88 | 89 | return true; 90 | } 91 | 92 | /** 93 | * Process all dem errors. 94 | * 95 | * @param validator 96 | * @param errors 97 | * @param field_map 98 | */ 99 | export function errorProcessor(validator, errors, field_map) { 100 | let keys = Object.keys(errors); 101 | let field_keys = Object.keys(field_map); 102 | 103 | for(let i = 0; i < keys.length; i++) { 104 | let field = null; 105 | 106 | if (field_keys.includes(keys[i])) { 107 | field = field_map[keys[i]]; 108 | } else { 109 | field = keys[i]; 110 | } 111 | 112 | if (!field) { 113 | continue; 114 | } 115 | 116 | errors[keys[i]].forEach(function (msg) { 117 | validator.errors.add({ 118 | field: field, 119 | msg: msg 120 | }); 121 | }); 122 | } 123 | } 124 | 125 | /** 126 | * Get an option from our Options object 127 | * 128 | * @param option 129 | * @param options_bag 130 | * @param default_option 131 | * @returns {*} 132 | */ 133 | export function getOption(option, options_bag, default_option) { 134 | if (!option || !options_bag || !default_option) { 135 | return null; 136 | } 137 | 138 | if (options_bag[option] === undefined) { 139 | return default_option; 140 | } 141 | 142 | return options_bag[option]; 143 | } 144 | 145 | /** 146 | * Return the same kind of object no matter what driver 147 | * 148 | * @param response 149 | * @param driver 150 | * @returns {Promise} 151 | */ 152 | export function processResponseForDriver(response, driver) { 153 | return new Promise(function (resolve, reject) { 154 | if (!response || !driver) { 155 | reject('Response not properly provided.') 156 | } 157 | 158 | if (driver === 'axios') { 159 | resolve(response.response) 160 | } else if (driver === 'fetch') { 161 | response.json().then(function (json_data) { 162 | resolve({ 163 | status: response.status, 164 | data: json_data ? json_data : null, 165 | }); 166 | }); 167 | } else { 168 | reject('Driver not found.'); 169 | } 170 | }); 171 | } 172 | -------------------------------------------------------------------------------- /src/handleError.js: -------------------------------------------------------------------------------- 1 | import { 2 | validStatus, 3 | warning, 4 | fatalError, 5 | validFieldMap, 6 | responseHasErrors, 7 | errorProcessor, 8 | getOption, 9 | processResponseForDriver 10 | } from './core.js'; 11 | 12 | /** 13 | * 14 | * Handle an error. 15 | * 16 | * @param validator 17 | * @param response 18 | * @param field_map 19 | * @param options 20 | * @returns {void|*} 21 | */ 22 | function handleError(validator, response, field_map, options) { 23 | if (!field_map) { 24 | field_map = {}; 25 | } 26 | 27 | if (!options) { 28 | options = {}; 29 | } 30 | 31 | let driver = getOption('driver', options, 'axios'); 32 | let show_errors = getOption('show_errors', options, true); 33 | 34 | processResponseForDriver(response, driver).then(function (response) { 35 | 36 | if (!validator) { 37 | return fatalError('VeeValidate instance not found.', show_errors); 38 | } 39 | 40 | if (!response) { 41 | return fatalError('Response empty. Are you using the right driver?', show_errors); 42 | } 43 | 44 | if (Object.keys(field_map).length > 0 && !validFieldMap(field_map)) { 45 | return fatalError('Your field map was not valid.', show_errors); 46 | } 47 | 48 | if (!validStatus(response.status)) { 49 | if (response.status === 403) { 50 | warning('Response was not authorized.', show_errors); 51 | } 52 | 53 | warning('Response status did not meet expectations. Expecting: 422', show_errors); 54 | } 55 | 56 | if (!responseHasErrors(response.data)) { 57 | return warning('Response did not contain any Laravel errors.', show_errors); 58 | } 59 | 60 | errorProcessor(validator, response.data.errors, field_map); 61 | 62 | // Boom. 63 | }).catch(function (error) { 64 | return fatalError(error, show_errors) 65 | }); 66 | } 67 | 68 | export default handleError; -------------------------------------------------------------------------------- /src/handleFetchError.js: -------------------------------------------------------------------------------- 1 | import handleError from './handleError.js'; 2 | 3 | /** 4 | * 5 | * Handle an error. 6 | * 7 | * @param validator 8 | * @param response 9 | * @param field_map 10 | * @param options 11 | * @returns {void|*} 12 | */ 13 | function handleFetchError(validator, response, field_map, options) { 14 | if (!field_map) { 15 | field_map = {}; 16 | } 17 | 18 | if (!options) { 19 | options = {}; 20 | } 21 | 22 | options['driver'] = 'fetch'; 23 | return handleError(validator, response, field_map, options); 24 | } 25 | 26 | export default handleFetchError; 27 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------