Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jrdavidson's avatar

Working with jQuery and Laravel On Deleting Item

This is currently how I have my destroy method in my UsersController. Once this method is reached I would like for it to verify that the id is an integer and verify that it belongs to a user in the database. If it is neither an integer or belongs to a user in the database I would like for it to 404 error.

If the user is found I would like for it to delete the record from the database which I currently have set up for soft deleting and delete the user's profile record which I also have it set up for soft deleting. Its tied together by a relationship.

At first I had this method being reached with a form in a table with a however I wanted to also have it display a bootstrap modal asking for confirmation and if the user pressed yes then the destroy method was to be ran and then I'm thinking the page was to be refreshed. The HTML table is using the jQuery Datatables plugin. When the table or window was refreshed I was going to display a Growl message that says the item was successfully deleted.

What would you do to improve this code?

<?php

class UsersController extends BaseController {
        /**
     * Remove the specified user from the database.
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id)
    {
        // Retrieve user object from database with passed parameter or give error.
        $user = User::findOrFail($id);

        // Delete user object from database.
        $user->delete();

        // Delete user's profile from database.
        $user->profile->delete();

        // Redirect to user's index method.
        return Redirect::route('backstage.users.index');
    }
}
$(document).ready(function(){
    $('#basicTable').DataTable({ 
        "aoColumnDefs": [
            { "bSortable": false, "aTargets": [ "nosortable" ] }
    ],
    "order": []
    });
   $(function()
    {
        var $modal = $('#deleteModal');
        // runs when a user first hits a delete link
        $('.js-ajax-delete').on('click', function(e)
        {
            // Stop anchor tag from trying to execute as a link
            e.preventDefault();

            // Get delete URL
            var deleteUrl = $(this).attr('href');

            // Show delete confirmation modal
            $modal.modal('show');

            // If user clicks "Yes" then submit deletion
            $('#deleteModalConfirm').on('click', function(e)
            {
                // Close modal
                $modal.modal('hide');

                // Do delete
                $.post(deleteUrl, {"_method" : "DELETE"}, function(response) {
                    // This is a callback. Do stuff here if you want.
                    console.log('testing');
                });
            });
        });
    });
});
<a data-original-title="Delete" href="{{ route('backstage.users.destroy', $user->id) }}" data-toggle="tooltip" title="" class="tooltips js-ajax-delete"><i class="fa fa-trash-o"></i></a>
0 likes
10 replies
thepsion5's avatar

One thing that might be an issue - you may be assigning a new event handler every time an href is clicked, meaning the 2nd time you'd fire 2 AJAX requests, the 3rd time would be 3, etc. You can probably solve that by using JS to attach the URL to the modal via a data attribute, something like this:

var $modal = $('#deleteModal');
$('.js-ajax-delete').on('click', function(event)
{
    var deleteUrl = $(this).attr('href');
    $modal.data('delete-url', deleteUrl);
    $modal.modal('show');
});

$('#deleteModalConfirm').on('click', function()
{
    $modal.modal('hide');
    var deleteUrl = $modal.data('delete-url');
    $.post(deleteUrl, {"_method" : "DELETE"}, function(response) {
         //handle successful/failed delete
     });
});

Abstract it to a function so you don't have to hard code the selectors, like so:

function setupDeleteModalLinks(linkSelector, modalSelector, modalConfirmSelector)
{
    /* your code here */
}

And then you can call it in your blade files like so:

<script type="text/javascript">
$(function()
{
    setupDeleteModalLinks('.js-ajax-delete', '#deleteModal', '#deleteModalConfirm');
});
</script>

In addition to the benefits of being better abstracted, it also means your selectors are located in the same file as the javascript that relies on them.

jrdavidson's avatar

Do you think my HTML link and controlled code is acceptable?

jrdavidson's avatar

I have not dealt with abstracting the code to a function yet but I will. I want to make sure all functionality works before doing so. So far with what you suggested with adding the delete-url part to the modal works great however with what I have now I receive two responses. One is a POST request http://myapp.app/application/users/2 and a GET request http://myapp.app/application/users. Not sure if I really should be or not. Also it is not refreshed my page after it does it. It soft deletes the user from the database as desired but after it does it still shows the record in the HTML table.

jrdavidson's avatar

Also the only other issue is I was going to try and use the same modal for dropping down when the user creates/edits a record. So I"m trying to figure out what I would have to change so that I can keep the same modal and just modify certain parts of it when loaded with jQuery.

ArraySync's avatar

Well my first speculation would be that your $.ajax type is 'post', if your trying to trigger a delete, it should be 'delete'

thepsion5's avatar

Alternatively, submit a POST request but include the field _method with the value DELETE, which is how Laravel's form helpers work.

jrdavidson's avatar

I'm sorry @thepsion5 I didn't include the updated code. I am receiving a 405 Method Not Found error message. When I execute the code below.

function runConfirmation()
{
    /*
    var takoTuesday = confirm("Are you sure you want to delete that");
    if(takoTuesday == true)
    {
        alert("* * * Posting data back to Model * * *\n * * * Boop Beep Boop * * * \n\n\n\n * * * Ding * * *");
        chacia_table_manip_good.fnDeleteRow(chacia_table_manip_good.fnGetPosition(chacia_row_to_delete));
    }
    else
    {
        alert('* * * Canceling Request * * *');
    }*/

    $('#myModal .modal-body p').html('Are you sure you want to delete this item?');

    $('#myModal').modal('show');

    $('#myModalConfirm').on('click', function(e) {
         var url = $('#myModal').data('url');
         $.ajax({
             type: 'post',
             url: url,
             data: { _method: 'DELETE' },
             success: function(response) {
                 $.gritter.removeAll();
                 var className = 'growl-danger';
                 if (response.status == "SUCCESS") {
                    className = 'growl-success';
                 }
                 $.gritter.add({
                    position: 'top-right',
                    fade_in_speed: 'medium',
                    fade_out_speed: 2000,
                    time: 6000,
                    title: response.title,
                    text: response.message,
                    class_name: className,
                    sticky: false
                 });
             }
         });

         $('#myModal').modal('hide');
     });
}

Please or to participate in this conversation.