Are You Sure?
All we know the confirmation dialog boxes to be prompted to the user - e.g. on deletion actions - and for my Laravel applications I've consolidated an approach a bit more articulated then the classic (and ugly, and poorly informative) confirm('Are you sure?')
attached to some submit
or click
Javascript event.
What I do is:
- prepare an
askdestroy
route in my controller, returning a Bootstrap Modal - the modal contains proper graphics, informative text customized by the type of Model to be removed (e.g. Removing this, will be removed also that or Removing this, that will happen), and a form which action is the actual
destroy
route for the same Model. Sometime the form also has some addictional operation configurable by the user (e.g. This category is going to be removed, which other category assign to existing belonging items?) then performed in thedestroy
function of the controller - to the "Delete" button in the main interface, I attach the fetch and display of the modal in the
askdetroy
route
Using Larastrap for the Bootstrap modal and jBob for the client-side interaction of fetch + display of the same modal, most of the boilerplate code is then reduced to a new default route in my resource controllers and a few Blade templates.
// The route
Route::get('item/askdestroy/{id}', [ItemController::class, 'askdestroy'])->name('item.askdestroy');
// The function
public function askdestroy($id)
{
$item = Item::find($id);
return view('items.askdestroy', compact('item'));
}
// The modal
<x-larastrap::modal>
<x-larastrap::form :action="route('item.destroy', $item->id)" method="DELETE">
Are you sure?
</x-larastrap:form>
</x-larastrap::modal>
// The trigger
<x-larastrap::link label="Delete" color="danger" classes="async-modal" :href="route('item.askdestroy', $item->id)" />
To reduce even further the boilerplates, I've started introducing my own special resource controllers automatic routing to add the askdestroy
route by default (with the existing create
, edit
and so on). This can be done injecting a custom ResourceRegistrar
into your own application container, able to handle the addictional route.
In AppServiceProvider
I've added
use Illuminate\Routing\ResourceRegistrar;
use App\Services\ExtraResourceRegistrar;
use Illuminate\Routing\Router;
public function register()
{
$this->app->bind(ResourceRegistrar::class, function ($app) {
return new ExtraResourceRegistrar($app->make(Router::class));
});
}
And then, in app/Services/ExtraResourceRegistrar.php
file:
<?php
namespace App\Services;
use Illuminate\Routing\ResourceRegistrar;
use Illuminate\Routing\Router;
class ExtraResourceRegistrar extends ResourceRegistrar
{
public function __construct(Router $router)
{
parent::__construct($router);
/*
In ResourceRegistrar, $resourceDefaults is an array containing all the
default routes to be managed for resource controllers.
Here we append the new 'askdestroy'
*/
$this->resourceDefaults[] = 'askdestroy';
}
/*
Each default route must have his own addResource* function, which defines
the actual URL of the route, the name and so on
*/
protected function addResourceAskdestroy($name, $base, $controller, $options)
{
$name = $this->getShallowName($name, $options);
$uri = $this->getResourceUri($name).'/{'.$base.'}/askdestroy';
$action = $this->getResourceAction($name, $controller, 'askdestroy', $options);
return $this->router->get($uri, $action);
}
}
Now askdestroy
route is added to all Route::resource('items', ItemController::class);
Sooner or later I will pack all of this in a package...