DEV Community

Jake Casto
Jake Casto

Posted on

Laravel Nova: Adding custom buttons to resource toolbars

header image
If you've seen issue 786 on laravel/nova-issues on Github or attempted to add custom buttons to Resources in Laravel Nova you are probably frustrated. I spent a whole day trying to figure this out. But it's a lot simpler than you think!

Laravel Nova is powered by Vue.JS a very powerful JS microframework. Each resource has a custom component and that component has its own scope. This allows us to override Nova's built-in components and add custom buttons.

Let's start by creating a new Nova Resource Tool:



php artisan nova:resource-tool 0x15f/custom-resource-toolbar


Enter fullscreen mode Exit fullscreen mode

Say yes to all of the prompts...

Now that you've created your resource tool navigate to the nova-components/custom-resource-toolbar/resources/js directory open tool.js in your favorite JS editor and paste the following.



Nova.booting((Vue, router) => {
    Vue.component('custom-detail-toolbar', require('./components/CustomDetailToolbar'));
    Vue.component('quotes-detail-toolbar', require('./components/QuotesDetailToolbar'));
})


Enter fullscreen mode Exit fullscreen mode

Navigate into the components directory and delete Tool.vue. Now create two files, one named CustomDetailToolbar.vue the other named QuotesDetailToolbar.vue. Paste the following into CustomDetailToolbar.vue:



<template>
    <div class="flex w-full justify-end items-center mx-3">
        <component v-if="hasComponent" :is="component" />
    </div>
</template>

<script>
    export default {
        props: ['resourceName', 'resourceId'],
        computed: {
            component(){
                return this.resourceName + '-detail-toolbar';
            },
            hasComponent()
            {
                return this.component in this.$options.components;
            }    
        }
    }
</script>


Enter fullscreen mode Exit fullscreen mode

And paste the following into QuotesDetailToolbar.vue:



<template>
    <div>
        <div class="flex w-full justify-end items-center">
           <a
                class="btn btn-default btn-icon btn-white"
                :href="'/nova-vendor/custom-resource-toolbar/export-quote/' + this.$parent.resourceId"
                style="background-color: var(--primary); color: white;">
                Export as PDF
             </a>
        </div>
    </div>
</template> 

<script>
    export default {
        props: ['resourceName', 'resourceId', 'field'],
        mounted() {
            var elements = document.getElementById('nova').querySelectorAll('h4');
            [].forEach.call(elements, function(element) {
                if(element.innerHTML === 'Custom Detail Toolbar') {
                    element.parentNode.remove();
                }
            });
        }
    }
</script>


Enter fullscreen mode Exit fullscreen mode

You can now build your Resource Tool using npm run watch, add it to your Resources, and open your CustomResourceToolbar.php file and change the component name to custom-detail-toolbar. I'll explain what we did below.

In tool.js we registered two new components custom-detail-toolbar and quotes-detail-toolbar, custom-detail-toolbar is used by Nova to load any components that should be displayed on that toolbar. Nova then looks for the resource's toolbar. You can define your resources toolbar component by registering a component with your resources plural name followed by -detail-toolbar. Within that component, you can add any CSS/JS that should be placed in the toolbar.

If you notice I have a mounted function in my component with the following code:



mounted() {
    var elements = document.getElementById('nova').querySelectorAll('h4');
    [].forEach.call(elements, function(element) {
        if(element.innerHTML === 'Custom Detail Toolbar') {
            element.parentNode.remove();
        }
    });
}


Enter fullscreen mode Exit fullscreen mode

Typically a resource tool has a panel on your resource detail page. This function runs when our component has been mounted to remove the panel that nova adds giving your page a clean feel.

You can find all the code used in this tutorial on github.

Note: I quickly wrote this article, I'll clean it up later.

Top comments (11)

Collapse
 
palpalani profile image
Palaniappan

Hi,

I want try this tool,but when install i am getting the following namespace parser error.

In ToolServiceProvider.php line 3:

syntax error, unexpected '0x15f' (T_LNUMBER), expecting identifier (T_STRING)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
emillkaakillme profile image
Emil

Fixed!
Just removed a vendor dir in project (rm -rf vendor)
Then run composer update

And try to create a new nova resourse-tool with following command:
php artisan nova:resource-tool my-vendor-name/custom-resource-toolbar

'my-vendor-name' should be in kebab case

It helped me, hope it will help you

Collapse
 
emillkaakillme profile image
Emil

After I run your command:
php artisan nova:resource-tool 0x15f/custom-resource-toolbar
The artisan in my project stopped working...

It always reports an error with this wierd thing

In case if you know how to fix it please let me know!

Collapse
 
briavers profile image
Brian Verschoore

what do you mean with add it to your Resources?

Collapse
 
camaech profile image
Cam Heikkinen

This is the important part: "You can define your resources toolbar component by registering a component with your resources plural name followed by -detail-toolbar."

So in my case, I was using for an Article nova resource. So I changed the 'quotes-detail-toolbar' to 'articles-detail-toolbar'. That's it. You don't even need to add it as a tool, like you do with most other Nova tools in your NovaServiceProvider.

The button will now show up in your Resource (url should be something like: '/resources/articles/76'), assuming you ran 'npm run dev' on your tool.

Collapse
 
hemnyos profile image
Hemnyos

hi ! i'm so sorry, i'm learning laravel and i dont understand where i can add my button. I mean i did all of things at top, but event a random button doesnt appeared x3

Collapse
 
jake profile image
Jake Casto

Yes! When you add the resource tool to the model use the canSee method you use to hide fields and stuff. More info here

Collapse
 
it3krakow profile image
IT-3

Hello,
great job !
I do this in the Index page - and it works perfectly!
I have one question, maybe you have any idea how to add to button permissions?
On the detail page I can use withMeta method, but is there any way to pass the permission to do the action on index page ?

Collapse
 
milkhan profile image
Milkhan

Thank you for this tutorial but can you please explain how to use this on a resource? Thank you!

Collapse
 
camaech profile image
Cam Heikkinen

This is the important part: "You can define your resources toolbar component by registering a component with your resources plural name followed by -detail-toolbar."

So in my case, I was using for an Article nova resource. So I changed the 'quotes-detail-toolbar' to 'articles-detail-toolbar'. That's it. You don't even need to add it as a tool, like you do with most other Nova tools in your NovaServiceProvider.

The button will now show up in your Resource (url should be something like: '/resources/articles/76'), assuming you ran 'npm run dev' on your tool.

Collapse
 
ibet7o profile image
Roberto Ramírez

This is really simple! thank you very much.