5
votes

Let's say, I want to replace the nova/resources/js/components/Form/FieldWrapper.vue with a custom one (add some CSS classes or add additional HTML), how to do this, without making changes to the /nova directory (to be able to update nova)?

The usecase for changing the edit view is for example:

  • to add a "*" sign to a field, if its a mandatory field
  • to change the "one field per row" style to a "two fields per row" style to use the huge wasted empty space and reduce the height of the form to reduce scrolling
2
any update? did you manage to make it work? @bernhardh - Eran Levi
Nope. As far as I know, its not possible - bernhardh

2 Answers

1
votes

inside nova folder change file :

webpack.mix.js.dist to webpack.mix.js

enter to nova folder and do:

npm install
npm run watch

and then go to folder nova\resources\js

go change vue component do you need

after then run (on your root project):

php artisan nova:publish
0
votes

the easiest way to override laravel nova vue files is to create a tool, and load a component with the same name as the component you want to override.

In my case, i was creating a custom Nova action, laravel Nova doesn't support custom actions but you can do it anyway. In order for the custom Action to work, i need to override 2 laravel nova vue files. let me walk you through how i did it.

i started by creating a custom tool with the command php artisan nova:resource-tool vendor/package-name. change the vendor and package name to your preference. The above command will create your tool folder and the nova-components folder in the root of your Laravel Project.

Under the src folder of your tool, you have the service provider class and the main tool class, my tool service provider looks like this

<?php

namespace TestTool\DataExportAction;

use Laravel\Nova\Nova;
use Laravel\Nova\Events\ServingNova;
use Illuminate\Support\ServiceProvider;

class ActionServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Nova::serving(function (ServingNova $event) {
            Nova::script('data-export-action', __DIR__.'/../dist/js/action.js');
        });
    }
}

as you can see am only serving a js file.

My main tool class named DataExportAction.php looks like this

<?php

namespace TestTool\DataExportAction;

use Laravel\Nova\Actions\Action;
abstract class DataExportAction extends Action
{
    /**
     * The filter's component.
     *
     * @var string
     */
    public $component = 'data-export-action';
}

as you can see, extending the laravel Nova action base class located at nova/src/Actions/Action.php and am overriding the vue component name here public $component = 'data-export-action';

In the tool resources/js folder, i have the main tool.js file which i renamed to action.js and a components folder where we will place the vue components that will override the main Nova vue files.

in the action.js file i have this

Nova.booting(Vue => {
    Vue.component('data-export-action',  require('./components/ConfirmActionModal'));
}) 

note the component name is the same as the one defined in DataExportAction class

now in order to use the custom class, i create the default nova action class and instead of extending the nova/src/Actions/Action.php class, i extend the DataExportAction class and it will automatically use my custom component when loading the action.

now, in order to get more control over the action, i also need to override a Vue component located at nova/resources/js/components/ActionSelector.vue. if you check the main nova components file located at nova/resources/js/components.js, the component is loaded like this

...

import ActionSelector from '@/components/ActionSelector'

Vue.component('action-selector', ActionSelector)

...

create an ActionSelector.vue file in the tool components folder with the contents of nova/resources/js/components/ActionSelector.vue. then in action.js file, add the line

Vue.component('action-selector', require('./components/ActionSelector'));

now the action.js file will look like

Nova.booting(Vue => {
    Vue.component('data-export-action', require('./components/ConfirmActionModal'));
    Vue.component('action-selector', require('./components/ActionSelector'));
})

note that we don't change the component name, now when Nova loads the action-selector component, it will load our custom component instead of the default one

if you try to run npm to compile the js of the tool we just created you will get an error because the component we are overriding requires files that are only in the Nova node_modules folder, to solve this, we edit our webpack.mix.js that looks like this

let mix = require('laravel-mix')

mix.setPublicPath('dist')
    .js('resources/js/action.js', 'js');

to this

let mix = require('laravel-mix')

mix.setPublicPath('dist')
    .js('resources/js/action.js', 'js')
    .webpackConfig({
        resolve: {
            alias: {
                '@/storage': path.resolve(__dirname, '../../nova/resources/js/storage'),
                '@': path.resolve(__dirname, '../../nova/resources/js/'),
            },
            modules: [
                path.resolve(__dirname, '../../nova/node_modules/'),
            ],
            symlinks: false
        },
    });

so instead of using our tools node_modules folder, we use the one in nova/

webpack should now compile successfully.

We have successfully overridden a Laravel Nova vue file

If you have questions, comment below, Cheers!!