loading...

Laravel Nova: Adding custom buttons to resource toolbars

jake profile image Jake Casto ・3 min read

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

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'));
})

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>

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>

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();
        }
    });
}

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.

Posted on by:

Discussion

markdown guide
 

thanks for sharing this , really great .

I was following the issue on GitHub and I was looking for a way to add authorization to the buttons , is there a way around it ?

I have polices but how I can get that in vuejs component ?

thank you so much .

 

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

 

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)
 

what do you mean with add it to your Resources?

 

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.

 

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 ?

 

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

 

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.