© 2024 Flywheel Co.
I wrote about Laravel Nova in October of 2018, close to when it was first released. At Flywheel, we adopted it pretty quickly and used it for both internal and client projects. Now that we’ve had more time with it, our clients have had more time with it, and the code base has matured, I thought it would be a good time to update how we’ve been feeling about Laravel Nova in general and how we’ll utilize it for our projects in the future.
Let me start off by saying Laravel Nova has gotten a lot better for us. If you read my first post you’ll know that we had a lot of good things to say and some areas where we needed improvement for it to be viable in our business. We liked how it integrated quickly and easily with our existing Laravel projects but we had issues with some of the user experience and how we would use it as a client facing administration panel. We use Nova for internal projects as well as client facing applications where it makes sense so we’re coming from both perspectives. There were also times where we felt that extending Nova past its default offering could turn into a headache. I’m happy to say that many of those issues have been relieved and for the others we’ve found some solid workarounds.
In this post I want to share some of the tips and tricks I’ve found while working with Nova. Some of these are things we learned through using Nova and others are new features that weren’t available when writing the previous post.
What I’ll be touching on in this post
asHtml()
method/Resources are the life blood of Laravel Nova. You can think of a Resource as the management and display requirements for a Laravel model in your application. Check out our previous post on Nova to get a better idea of resources.
You can create a resource using Artisan :
php artisan nova:resource EventAttendees
If you have even a medium sized application your resource list in the Nova navigation will get out of control quickly. Luckily you can group and name resources to make everything a little more manageable. Using resource grouping you can cluster resources that are related to one another in a logical way. You can group resources by updating the static $group
class parameter on your resource.
public static $group = 'Event Management';
All resources with this same group name will be categorized alphabetically under this group. It’s a helpful way to keep things organized.
If your nova resource has relationships that need to be displayed on your index or detail screens you can eager load those relationships without touching your application’s model. Similar to eager loading a relationship on the model you can update the static $with
class parameter to load relationships.
public static $with = [‘profile’];
I’m going to be honest… I don’t use these. I thought they were interesting enough to add to this post but, in practice your mileage may vary. From the Laravel Nova documentation you can create a record from the resource index by pressing the C
key and you can update a record from the resource detail view by pressing the E
key. You might find that useful if you’re doing a ton of content population or just hate the mouse/trackpad.
In Nova you can create “Actions” that will do some sort of processing on a single or multiple rows in the database. Actions have been great from the beginning but the UI left quite a bit to be desired by not making it clear what actions were available or how to use them. Since Nova’s release there have been some great changes that make it much easier for clients and general users to understand actions and which ones are available.
You can create an action using Artisan :
php artisan nova:action IssueEventRefund
Praise the Nova gods… inline actions are now a thing. “What are inline actions?” you ask and why am I so excited? Well let me explain. The early iterations of Laravel Nova came with Resource Actions. Actions are essentially classes that you can use to perform some sort of processing on a model row (a single instance of a model in your application). These are phenomenal pieces of utility that I absolutely loved. The problem was in the UI implementation.
The only way to know if an action existed was to use the checkbox on individual rows. Only after you checked off one or more rows would you be presented with a dropdown at the top of the list for “Actions”. This wasn’t really a problem if you were the creator of the system… But try handing this over to a customer. Not knowing that an action was available until you “did something” was a really confusing thing for our clients. Not to mention the fact that the term “Actions” is pretty ambiguous.
Here’s a quick example. We have an e-commerce store that’s built in Laravel. If our client, the owner of the store, wanted to sign in and send a receipt for a purchase they would just have to know or remember that the functionality was there only if they selected the purchase (using the checkbox on the row) they wanted to send the receipt for first. This might seem like a small thing but it brought on a lot of headaches.
Inline actions are here to save the day. Most of the time, in our experience, we wanted actions to be visible on the row so that our customers and any users would know immediately that they could do something to the row. You can now set a parameter on your Action class to display the action in an inline dropdown button. Just set the $showOnTableRow
parameter to true
in your class and you’ll see a new dropdown button called “Actions” in your table.
public $showOnTableRow = true;
This is really helpful from a UI perspective because users don’t need to do anything to know that there is more functionality available. It may seem like a small thing, but this one was really big for us.
In earlier iterations of Nova you didn’t have the ability to change what the pop-up window said when a user wanted to perform an action. The buttons were “Run Action” and “Cancel” which is… fine. We always wanted more clarity, though. Now you can change the name of the action, the confirmation text (the text in the modal window), the confirm button text, and the cancel button text. This is really helpful for clarifying what’s happening after you click on the action itself.
If your action is used in one specific scenario or in only one context a good option is to update parameters on the action class itself.
public $name = 'Refund Attendee';
public $confirmText = 'Are you sure you want to refund this attendee?';
public $confirmButtonText = 'Yes, Issue a Refund';
public $cancelButtonText = 'Cancel';
public $showOnTableRow = true; // Show this action on the table row
If you’d like to change the text based on the implementation of the action you can update it in the actions()
method on your resource.
return [
(new Actions\ActivateAnnoucement)
->confirmText('Are you sure you want to refund this attendee?')
->confirmButtonText('Yes, Issue a Refund')
->cancelButtonText('Cancel'),
];
Cards are great pieces of information that you can display on your dashboards and resource detail views. By default, the cards available in Nova are Metrics. Metrics are used to display data suitable for a graph or a single value. There are three basic Metrics that can be implemented in cards out-of-the-box. Value Metrics (a single value represented in the card), Trend Metrics (a line graph with points at various intervals), and Partition Metrics (a pie chart of various values that are represented as percentages in the graph and values in the legend).
This is a small update but you might find it useful in certain scenarios where the name of the card and the value aren’t quite enough to explain what the card / metric represents. If you want to add more information for your users you can add some help text that will appear in the form of a small question mark in the bottom right corner of the card. To add help text you just need to add the help()
method to your card implementation.
return [
(new ProfilesAddedPerDay)->help('This represents how many profiles were added per day.’)
];
Cards are more than just value and chart metrics. You can create your own cards and add them into your Nova UI pretty easily. I’ll dive into more detail about creating your own cards and extending Laravel Nova in a future post. Check out the documentation for creating your own custom cards in Nova.
Fields in Nova are used to represent single columns in your database model and computed values on the model. Fields are super versatile and useful. You add fields to resources in the fields()
method of your resource class. A list of available fields can be found in the Nova documentation.
Here are a few basic tips that have been helpful in our experience with Nova.
If you’re storing JSON in your database you’ll find the Code
field to be very useful. By adding the json()
method to the Code
field Nova will automatically format your JSON values which makes editing a breeze.
Code::make('Data')->json(),
You can define various rules for fields on your resource. There are two ways to make a field required when adding and editing a resource. One way is by adding required
to your rules()
method like this :
Text::make(‘Email’)->rules(‘required’),
If you only want to make the field as required you can use the required()
method and pass a boolean value through to mark the field as required. Both of these examples do the same thing.
Text::make(‘Email’)->required(true),
This may or may not be petty, but one of my main frustrations with Nova is in the resource list. If you want to view a single resource you have to click on an eyeball icon in the far right-hand side of the row. Fair enough, but I really dislike having to click on such a small icon and the eyeball isn’t clear to many of our clients. One way we’ve gotten around this is by using a Text field with a callback that’s represented as HTML. It feels hacky and I hope that an official field of this nature eventually gets released. We’ll likely publish one in the next few days for our use cases.
Example implementation
Text::make('Name', function(){
return '<a href="/nova/resources/resource-identifier/'.$this->id.'" class="no-underline font-bold dim text-primary">'.$this->name.'</a>';
})->asHtml()->exceptOnForms(),
In this example we’re using a Text
field with a callback to produce the field value. We’re also using the asHtml()
method to make sure that Nova won’t strip html and the exceptOnForms()
method to make sure it’s only displayed on the resource index and resource detail views.
Be aware that it’s a bit of a manual process… Make sure you get the correct resource-identifier
for the link. You can use Tailwind for styling. The example above will use the Nova primary text color, will bold the text, will not have an underline, and will dim the color of the text on hover.
One more note : In this example this field is representing the Name
on the resource. If you need to be able to edit the name you’ll need to add another field that is only displayed on forms. For this example you would also add :
Text::make('Name')->onlyOnForms();
This will display an editable field that is only visible on forms. Like I said, it feels like a bit of a hack and a package for this type of field would be really useful (if it doesn’t already exist). If we release one, we’ll update this blog post with a link to it.
You’d be surprised to find out that it’s not all that clear how you can add a default value to your Nova Resource fields. There are a few different ways that people go about it but the only one that truly works doesn’t involve Nova at all. This is kind of a sticky point for me. I really like that Nova lives in Novaland and rarely requires you to modify your application code for Nova’s sake. In this case, though, you’ll need to make a small change to your Resource Model in your application code.
Here’s what I’m talking about Let’s say you have an e-commerce store and you want to set a default value for the price of the new products you’re adding. When you add a new product your nova field won’t have a value preset in it. If you want one, you’ll need to make a small change to your application’s model for your products.
protected $attributes = [
'price' => 300 // In cents == $3.00
];
Setting this on your application’s model will add a default, but overwrite-able value to your field. You might see some other options out in internet land about using the ->meta(['value' => 300])
method on your field. This is an option but you’ll find some finicky behavior when you want to change the value. I highly recommend setting the $attributes
parameter on your application’s model class.
When Nova was first released there weren’t many (if any) options for using a responsive template. Luckily, theming Nova has gotten significantly better since release if you’d like to roll-your-own. If you’d rather drop a package in and call it a day there is a great package that makes accessing your Nova backend on your phone much, much nicer. I would suggest you try GitHub - gregoriohc/laravel-nova-theme-responsive: A Laravel Nova responsive theme by Gregorio Hernández Caso.
The team behind Nova did a great job of pre-planning to make sure that the ecosystem would have a solid list of packages available that range form basic fields to themes. I recommend digging around through Nova Packages for some quality, easy installs that will make your Nova installation better and better. In following posts we’ll list out some of our favorite packages and we’ll also have some packages that we’ll be releasing on our own.
If you’re interested in creating your own Laravel Nova packages for single projects or to release to the public take a look at the documentation. It’s a bit daunting at first but, trust me, give it a shot and you’ll get it sorted out pretty quickly.
This is a long post that barely even scratches the surface of Laravel Nova. It’s a very flexible system but, in fairness, there is a decent learning curve. If you’re comfortable with Laravel you’ll have a much easier time figuring out Nova and integrating it into your workflow. If you’re new to both, just give it time and make sure you read the documentation fully.
If you’re on the fence and you have a decent use case for it I would highly recommend giving Nova a shot. I’ve enjoyed using it since release and I’ve been using it every day since. We have a very complex application that has gotten a TON of mileage out of Nova. It’s been an invaluable tool for projects like that. If you love Laravel, you’ll likely love Nova for all of the same reasons.
We would love to hear from you on our Twitter or you can always contact us from our contact form.
Be good to each other out there!
Matt Higgins
Matt is a co-founder, creative director, and programmer at Flywheel. He's made literally tens of people laugh in his lifetime and is always looking for the next problem to solve.