├── .gitignore ├── README.md ├── composer.json ├── detailPreview.png ├── dist ├── css │ └── field.css └── js │ └── field.js ├── formPreview.png ├── indexPreview.png ├── mix-manifest.json ├── package.json ├── resources ├── js │ ├── components │ │ ├── DetailField.vue │ │ ├── FormField.vue │ │ └── IndexField.vue │ └── field.js └── sass │ └── field.scss ├── src ├── Checkboxes.php └── FieldServiceProvider.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | composer.phar 5 | composer.lock 6 | package-lock.json 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Nova Checkboxes Field 2 | 3 |  4 | 5 |  6 | 7 |  8 | 9 | ## Package maintenance 10 | 11 | Unfortunately I am no longer actively working in the Laravel ecosystem and as such am unable to maintian this package. If anyone would like to take over the maintenance of the package please get in touch (open an issue or contact me on [Twitter](https://twitter.com/m2de_io)). 12 | 13 | ## Installation 14 | 15 | `composer require silvanite/novafieldcheckboxes` 16 | 17 | ## Usage 18 | 19 | ```php 20 | use Silvanite\NovaFieldCheckboxes\Checkboxes; 21 | 22 | Checkboxes::make('Permissions')->options([ 23 | 'viewNova' => 'Access Admin UI', 24 | 'manageUsers' => 'Manage Users', 25 | ]), 26 | ``` 27 | 28 | ## Configuration 29 | 30 | You can customise how the values from checkbox fields are passed to your scripts. By default it's will cast all numeric keys to floats or integers, e.g. `[1, 2, 3]` instead of `["1", "2", "3"]`. You can save disable this feature by calling `withoutTypeCasting()` to have the original array keys returned unmodified. 31 | 32 | ```php 33 | use Silvanite\NovaFieldCheckboxes\Checkboxes; 34 | 35 | Checkboxes::make('Permissions')->options([ 36 | 1 => 'Access Admin UI', 37 | 2 => 'Manage Users', 38 | ])->withoutTypeCasting(), 39 | ``` 40 | 41 | You can also customise the number of columns in which options will be displayed by calling `columns()` 42 | 43 | ```php 44 | use Silvanite\NovaFieldCheckboxes\Checkboxes; 45 | 46 | Checkboxes::make('Permissions')->options([ 47 | 1 => 'Access Admin UI', 48 | 2 => 'Manage Users', 49 | ])->columns(4), 50 | ``` 51 | 52 | ### Example using eloquent 53 | 54 | Here is an example of how you might use an eloquent model with Checkboxes. 55 | 56 | ```php 57 | use Silvanite\NovaFieldCheckboxes\Checkboxes; 58 | 59 | Checkboxes::make('users') 60 | ->options(App\User::pluck('name', 'id')) 61 | ->withoutTypeCasting(), 62 | ``` 63 | 64 | ## Support 65 | 66 | If you require any support please contact me on [Twitter](https://twitter.com/m2de_io) or open an issue on this repository. 67 | 68 | ## License 69 | 70 | MIT 71 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silvanite/novafieldcheckboxes", 3 | "description": "A Laravel Nova field to display a number of multi-select options using checkboxes.", 4 | "keywords": [ 5 | "laravel", 6 | "nova", 7 | "input", 8 | "field", 9 | "checkbox", 10 | "checkboxes", 11 | "multiselect", 12 | "multiple choice" 13 | ], 14 | "license": "MIT", 15 | "require": { 16 | "php": ">=7.1.0" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "Silvanite\\NovaFieldCheckboxes\\": "src/" 21 | } 22 | }, 23 | "extra": { 24 | "laravel": { 25 | "providers": [ 26 | "Silvanite\\NovaFieldCheckboxes\\FieldServiceProvider" 27 | ] 28 | } 29 | }, 30 | "config": { 31 | "sort-packages": true 32 | }, 33 | "minimum-stability": "dev", 34 | "prefer-stable": true 35 | } 36 | -------------------------------------------------------------------------------- /detailPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novafieldcheckboxes/4e0372126221f50a47a74595d3ed73e169347910/detailPreview.png -------------------------------------------------------------------------------- /dist/css/field.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novafieldcheckboxes/4e0372126221f50a47a74595d3ed73e169347910/dist/css/field.css -------------------------------------------------------------------------------- /formPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novafieldcheckboxes/4e0372126221f50a47a74595d3ed73e169347910/formPreview.png -------------------------------------------------------------------------------- /indexPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novafieldcheckboxes/4e0372126221f50a47a74595d3ed73e169347910/indexPreview.png -------------------------------------------------------------------------------- /mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/dist/js/field.js": "/dist/js/field.js", 3 | "/dist/css/field.css": "/dist/css/field.css" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@silvanite/novafieldcheckboxes", 3 | "version": "1.2.2", 4 | "private": true, 5 | "scripts": { 6 | "dev": "npm run development", 7 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 8 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "watch-poll": "npm run watch -- --watch-poll", 10 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 11 | "prod": "npm run production", 12 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 13 | }, 14 | "devDependencies": { 15 | "cross-env": "^5.0.0", 16 | "laravel-mix": "^1.0", 17 | "laravel-nova": "^1.0" 18 | }, 19 | "dependencies": { 20 | "vue": "^2.5.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/js/components/DetailField.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 13 | 17 | {{ label }} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 38 | 39 | 47 | -------------------------------------------------------------------------------- /resources/js/components/FormField.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | {{ firstError }} 29 | 30 | 31 | 32 | 33 | 34 | 80 | 81 | 89 | -------------------------------------------------------------------------------- /resources/js/components/IndexField.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 34 | -------------------------------------------------------------------------------- /resources/js/field.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.devtools = true 4 | 5 | Nova.booting((Vue, router) => { 6 | Vue.component('index-novafieldcheckboxes', require('./components/IndexField')); 7 | Vue.component('detail-novafieldcheckboxes', require('./components/DetailField')); 8 | Vue.component('form-novafieldcheckboxes', require('./components/FormField')); 9 | }) 10 | -------------------------------------------------------------------------------- /resources/sass/field.scss: -------------------------------------------------------------------------------- 1 | // Nova Tool CSS 2 | -------------------------------------------------------------------------------- /src/Checkboxes.php: -------------------------------------------------------------------------------- 1 | 2, 24 | ]; 25 | 26 | /** 27 | * Specify the number of columns. 28 | * 29 | * @param array $columns 30 | * @return self 31 | */ 32 | public function columns(int $columns) 33 | { 34 | return $this->withMeta(['columns' => $columns]); 35 | } 36 | 37 | /** 38 | * Specify the available options 39 | * 40 | * @param array $options 41 | * @return self 42 | */ 43 | public function options(array $options) 44 | { 45 | return $this->withMeta(['options' => $options]); 46 | } 47 | 48 | /** 49 | * Disable type casting of array keys to numeric values to return the unmodified keys. 50 | */ 51 | public function withoutTypeCasting() 52 | { 53 | return $this->withMeta(['withoutTypeCasting' => true]); 54 | } 55 | 56 | /** 57 | * Determine if the array keys should be converted to numeric values. 58 | */ 59 | private function shouldNotTypeCast() 60 | { 61 | return ( 62 | array_key_exists('withoutTypeCasting', $this->meta) 63 | && $this->meta['withoutTypeCasting'] 64 | ); 65 | } 66 | 67 | /** 68 | * Hydrate the given attribute on the model based on the incoming request. 69 | * 70 | * @param \Laravel\Nova\Http\Requests\NovaRequest $request 71 | * @param string $requestAttribute 72 | * @param object $model 73 | * @param string $attribute 74 | * @return void 75 | */ 76 | protected function fillAttributeFromRequest(NovaRequest $request, $requestAttribute, $model, $attribute) 77 | { 78 | if ($request->exists($requestAttribute)) { 79 | /** 80 | * When editing entries, they are returned as comma seperated string (unsure why). 81 | * As a result we need to include this check and explode the values if required. 82 | */ 83 | if (!is_array($choices = $request[$requestAttribute])) { 84 | $choices = collect(explode(',', $choices))->map(function ($choice) { 85 | return ($this->shouldNotTypeCast()) ? $choice : $this->castValueToType($choice); 86 | })->filter(function ($value) { 87 | /** 88 | * Filtering out "falsy" values but allowing for int value zero (0) 89 | */ 90 | return $value === 0 ? true : $value; 91 | })->all(); 92 | } 93 | 94 | $model->{$attribute} = $choices; 95 | } 96 | } 97 | 98 | /** 99 | * Because we are having to explode the string value returned from Nova/Vue, we assume that any 100 | * numeric value should be returned as such, instead of a string. 101 | * 102 | * @param mixed $value 103 | * @return mixed 104 | */ 105 | private function castValueToType($value) 106 | { 107 | if (ctype_digit($value)) { 108 | return intval($value); 109 | } 110 | 111 | if (is_numeric($value)) { 112 | return floatval($value); 113 | } 114 | 115 | return $value; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/FieldServiceProvider.php: -------------------------------------------------------------------------------- 1 |
4 | 8 | 13 | 17 | {{ label }} 18 | 19 | 20 |
28 | {{ firstError }} 29 |