Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Want to send a DELETE request when outside of a form? This will handle the form-creation bits for you dynamically, similar to the Rails implementation. (Requires jQuery, but doesn't have to.) To use, import script, and create a link with the `data-method="DELETE"` attribute.
/*
<a href="posts/2" data-method="delete"> <---- We want to send an HTTP DELETE request
- Or, request confirmation in the process -
<a href="posts/2" data-method="delete" data-confirm="Are you sure?">
*/
(function() {
var laravel = {
initialize: function() {
this.methodLinks = $('a[data-method]');
this.registerEvents();
},
registerEvents: function() {
this.methodLinks.on('click', this.handleMethod);
},
handleMethod: function(e) {
var link = $(this);
var httpMethod = link.data('method').toUpperCase();
var form;
// If the data-method attribute is not PUT or DELETE,
// then we don't know what to do. Just ignore.
if ( $.inArray(httpMethod, ['PUT', 'DELETE']) === - 1 ) {
return;
}
// Allow user to optionally provide data-confirm="Are you sure?"
if ( link.data('confirm') ) {
if ( ! laravel.verifyConfirm(link) ) {
return false;
}
}
form = laravel.createForm(link);
form.submit();
e.preventDefault();
},
verifyConfirm: function(link) {
return confirm(link.data('confirm'));
},
createForm: function(link) {
var form =
$('<form>', {
'method': 'POST',
'action': link.attr('href')
});
var token =
$('<input>', {
'type': 'hidden',
'name': 'csrf_token',
'value': '<?php echo csrf_token(); ?>' // hmmmm...
});
var hiddenInput =
$('<input>', {
'name': '_method',
'type': 'hidden',
'value': link.data('method')
});
return form.append(token, hiddenInput)
.appendTo('body');
}
};
laravel.initialize();
})();
@muffycompo

This comment has been minimized.

Copy link

muffycompo commented Mar 7, 2013

Nice one Jeffrey, Thanks!

@ericlbarnes

This comment has been minimized.

Copy link

ericlbarnes commented Mar 8, 2013

Wonder if it would be easier to add an additional data* method for token?

<a href="posts/2" data-method="delete" data-token="{{ csrf_token() }} 
@JeffreyWay

This comment has been minimized.

Copy link
Owner Author

JeffreyWay commented Mar 8, 2013

Yeah, the embedded PHP is a temporary thing.

Maybe store the csrf token in a meta tag, and then just grab that value from the script. That way, the user never has to worry about passing the token custom attribute.

@tommymarshall

This comment has been minimized.

Copy link

tommymarshall commented Mar 8, 2013

Yep, grab that guy from a meta tag. Otherwise 👍

@alexrussell

This comment has been minimized.

Copy link

alexrussell commented Mar 8, 2013

Looks interesting, although I've always thought the best way around this is to define a new HTML helper function that spits out the form and button (with appropriate link styling or whatever) directly from PHP. Added bonus is that there's no bodging for the token, and non-JS people get the correct experience.

Incidentally, I've only ever seen one framework actually include this functionality for 'delete' action buttons (either using a 'proper' DELETE form or back when we just POSTed to a /delete and didn't pass a method or care about being RESTful) out of the box although can't currently remember which. Maybe Yii.

@dirkpostma

This comment has been minimized.

Copy link

dirkpostma commented Apr 23, 2013

I recently created an ajax way of sending DELETE requests. I'm a jQuery newbee (getting better using your tuts, thanks again!), but I gave it a try.

https://gist.github.com/dirkpostma/5442850

$(document).ready(function() {

// Add click handler to restful hyperlinks,
// e.g. to send DELETE requests
// Example:
// 
// <a href="/destroy/1" class="rest-delete">delete</a>
// <script>restful.init($('.rest-delete'));</script>
// 
var restful = {

    // TODO: add various configurations, e.g.
    // - do_confirm: [ true | false ]
    // - confirm_message: "Are you sure?"
    // - do_remove_parent: [ true | false ]
    // - parent_selector: '.li' '.div' ...
    // - success: (closure)

    init: function(elem) {
        elem.on('click', function(e) {
            self=$(this);
            e.preventDefault();

            if(confirm('Are you sure?')) {
              $.ajax({
                url: self.attr('href'),
                method: 'DELETE',
                success: function(data) {
                  self.parent('li').remove(); // todo: make configurable
                },
                error: function(data) {
                    alert("Error while deleting.");
                    console.log(data);
                }
              });
            };
        })
    },
}

restful.init($('.rest-delete'));
});
@franzose

This comment has been minimized.

Copy link

franzose commented Mar 22, 2014

Thanks!

@gpai

This comment has been minimized.

Copy link

gpai commented Apr 30, 2014

Thanks a bunch! This helped so much!

@cmd0315

This comment has been minimized.

Copy link

cmd0315 commented Aug 11, 2014

Hi Jeffrey! I just started using Laravel for my web app projects. Can you pls elaborate on your js script? Sorry, I am a bit confused. What link should I provide in the anchor tag? Same link as the one in the form prior to it or should I create another route that uses a different method in the controller? I am already using a form for the update process so I want the delete request to be done outside of it. Thanks.

@cavalor

This comment has been minimized.

Copy link

cavalor commented Aug 23, 2014

thanks!!! that helped me so much.

@dlm423

This comment has been minimized.

Copy link

dlm423 commented Sep 5, 2014

Thanks for this script, seems quite useful! I am having an issue, my <a> tag is redirecting me to another page, as opposed to submitting the DELETE request. I asked a question on Stack Overflow and hope to get some help in case anyone else runs into this issue. http://stackoverflow.com/questions/25695137/delete-request-outside-of-form-laravel/25695164

@kevinb1989

This comment has been minimized.

Copy link

kevinb1989 commented Nov 24, 2014

I don't know why I cannot implement this function. I use Debugbar and it displayed the error: View [posts.record] not found. Any idea?

@roNn23

This comment has been minimized.

Copy link

roNn23 commented Feb 12, 2015

Updated the script for Laravel 5 (the token-input was renamed to _token):
https://gist.github.com/roNn23/a86f31ecaf0c6e0a7d65

@lexdevelop

This comment has been minimized.

Copy link

lexdevelop commented Mar 3, 2015

Thanks, work like charm. You are the best Jeffrey :)

@rattfieldnz

This comment has been minimized.

Copy link

rattfieldnz commented Mar 12, 2015

What would be the be the best way to style the dialog/popup like a JQuery dialog/modal, with the script in laravel.js? I'm more of a back-end developer, so my Javascript knowledge needs improving...

@vpakg

This comment has been minimized.

Copy link

vpakg commented May 14, 2015

Perfect. I'm using laravel 4.2 and took me a while to realise that csrf_token has been renamed to _token, so I was getting a token mismatch. Same applies to laravel 5, but there are plenty of forks with the updated code.

As always, thanks again Jeffrey.

@raysn0w

This comment has been minimized.

Copy link

raysn0w commented May 16, 2015

Im curious, how did you guys managed to get this to work with the missing '$' before starting the function?

It doesnt work for me unless i add the '$'.

@8lbiasian

This comment has been minimized.

Copy link

8lbiasian commented May 22, 2015

how to make it work with L5 ?!

i try to change 'name': 'csrf_token', to 'name': '_token',

but i get

TokenMismatchException in VerifyCsrfToken.php line 46:

@soufianeEL

This comment has been minimized.

Copy link

soufianeEL commented Jun 4, 2015

updated to larevel 5
here

@tahertechs

This comment has been minimized.

Copy link

tahertechs commented Jul 10, 2015

You are genious.

@jeimz143

This comment has been minimized.

Copy link

jeimz143 commented Oct 27, 2015

hi im new in larave and mine got tokenMismatch can anyone guide me on how am i suppose to include it into my tag thanks :)

@xoco70

This comment has been minimized.

Copy link

xoco70 commented Nov 13, 2015

I get a View [places.show] not found.

I understand it, but don't know how to fix it.
In my routes, I use resource();
So, in my route list I have GET (route/{id}) --> Show
So, I don't understand well how should have 2 identical route for 2 actions ( GET (route/{id}) to show or delete)

Here are my route list

PUT | places/{places} | places.update | App\Http\Controllers\PlaceController@update | auth,auth |
| | PATCH | places/{places} | | App\Http\Controllers\PlaceController@update | auth,auth |
| | GET|HEAD | places/{places} | places.show | App\Http\Controllers\PlaceController@show | auth,auth |
| | DELETE | places/{places} | places.destroy | App\Http\Controllers\PlaceController@destroy | auth,auth |
| | GET|HEAD | places/{places}/edit | places.edit | App\Http\Controllers\PlaceController@edit | auth,auth |

@janzenz

This comment has been minimized.

Copy link

janzenz commented Jan 20, 2016

Got a problem with this where the link gets redirected instead of triggering the event. So I transferred e.preventDefault(); at the beginning of handleMethod method and it solved my problem.

@Chalkin

This comment has been minimized.

Copy link

Chalkin commented Feb 1, 2016

Thanks a lot guys! Works perfectly and saves lives!

@junkystu

This comment has been minimized.

Copy link

junkystu commented Mar 10, 2016

Something like this maybe?

<meta name="_token" content="{{ csrf_token() }}">

and then send it in the form:

 'value': $('meta[name="_token"]').attr('content')
@dialyy

This comment has been minimized.

Copy link

dialyy commented Apr 6, 2016

Folks using L5

Line 57 to 62
change ->

      var token = 
      $('<input>', {
        'type': 'hidden',
        'name': 'csrf_token',
          'value': '<?php echo csrf_token(); ?>' // hmmmm...
        });

to ->

      $('<input>', {
        'type': 'hidden',
        'name': '_token',
          'value': link.data('token')
        }); 
@alimranahmed

This comment has been minimized.

Copy link

alimranahmed commented May 11, 2016

^^
Thanks @dialyy

@neoplomero

This comment has been minimized.

Copy link

neoplomero commented May 14, 2016

@dialyy +1

@pastullo

This comment has been minimized.

Copy link

pastullo commented Jul 3, 2016

unbelievable! How crazy is that i need to paste 80 custom lines of Javascript to simply get a non-GET link to work?

Missing the super useful Rails helpers and the magic UJS:

link_to path, 'Delete', method: :delete

@MevlutOzdemir

This comment has been minimized.

Copy link

MevlutOzdemir commented Oct 4, 2016

Thanks @dialyy !!!

@ghost

This comment has been minimized.

Copy link

ghost commented Oct 8, 2016

Thx @dially

@jeffochoa

This comment has been minimized.

Copy link

jeffochoa commented Jan 5, 2017

How can you test this links on laravel ?

testSomeLink() { $this->visit('link')->see('result'); }

In this case I get a method not allowed exception.

Ideas ?

@act360

This comment has been minimized.

Copy link

act360 commented Apr 19, 2017

I tried to modify alert layout with other js library but when i click delete it does not wait for confirm to delete.can anybody give some idea on this?

@tmomin

This comment has been minimized.

Copy link

tmomin commented May 16, 2017

Cant seem to get this to work.

@extends('layouts.app')

@section('title', 'Search')

@section('content')
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="/js/laravel.js"></script>

    <div class="container theme-showcase" role="main">

        <!-- Main jumbotron for a primary marketing message or call to action -->
        <div class="jumbotron">
            <h1>Welcome to AKF Golf 2017</h1>
            <p>This site is to be used to check players on the of the tournament.</p>
        </div>

        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <table class="table table-striped table-hover">
                    <thead>
                    <tr>
                        <th>#</th>
                        <th>Name</th>
                        <th>Dollar Amount</th>
                        <th>Number of Players</th>
                        <th></th>
                        <th></th>
                    </tr>
                    </thead>
                    <tbody>
                    @foreach($sponsors as $sponsor)
                        <tr>
                            <td>{{ $sponsor->id }}</td>
                            <td>{{ $sponsor->name }}</td>
                            <td>${{ $sponsor->dollarAmount }}</td>
                            <td>{{ $sponsor->numOfPlayers }}</td>
                            <td><a href="{{ url('/sponsors', [$sponsor->id]) }}">Edit</a></td>
                            <td><a href="{{ url('/sponsors', [$sponsor->id]) }}" data-method="DELETE" data-confirm="Are you sure?">Delete</a></td>
                        </tr>
                    @endforeach
                    </tbody>
                </table>
            </div>
        </div>

    </div> <!-- /container -->

@endsection

<script src="https://cdnjs.cloudflare.com/ajax/libs/signature_pad/1.5.3/signature_pad.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
@antoniputra

This comment has been minimized.

Copy link

antoniputra commented Nov 28, 2017

I've made Javascript Vanilla version of this: https://gist.github.com/antoniputra/410af23ecc59b77d69dab0b2530718a1

no longer depend on jQuery anymore 😄

@kohlerdominik

This comment has been minimized.

Copy link

kohlerdominik commented Jan 22, 2018

This is a nice way for links. But for forms, in my opinion it's better to change the form attributes (and the "_method"-field if necessary). I couldn't find any solution for this, so i made my own script. It's built very like Jeffreys code.

Examples:

<input type="submit" value="Submit to alternative action" data-submit-action="/new-target">
<input type="submit" value="Submit to alternative target" data-submit-target="_blank">
<input type="submit" value="Submit as delete" data-submit-method="delete">
<input type="submit" value="Submit with confirmation" data-submit-confirmation="Are you sure?">
 {{ Form::submit('Submit alternative', [   'data-submit-action' => '/new-target',
                                        'data-submit-target' => '_blank',
                                        'data-submit-method' => 'delete',
                                        'data-submit-confirmation => 'Are you sure?'  ]); }}

I uploaded the full script to my own gist: https://gist.github.com/kohlerdominik/af78ecaec7a83e566e6fe8170f5f11bd

@hakankozakli

This comment has been minimized.

Copy link

hakankozakli commented Feb 11, 2018

If the event is not firing it is probably because document is not ready yet. Try this: https://gist.github.com/hakankozakli/3b76daa8cb49193f366178b98b64b71d

@a1iraxa

This comment has been minimized.

Copy link

a1iraxa commented Jul 4, 2018

This would even work in bootstrap-modal and dynamic inserted button.

https://github.com/a1iraxa/restful-delete-object

Return response must be:

{
    "success":true,
    "hide":false,
    "reload":false,
    "remove":false,
    "message":"Deleted!"
} 

Inspired by:
https://gist.github.com/dirkpostma/5442850

@nickdavies791

This comment has been minimized.

Copy link

nickdavies791 commented Sep 25, 2018

How would I then send any data that is outside of the form to the form, if the form is appended to the body?

i.e. I have multiple checkboxes in a table. How would these get sent to the form so they can be deleted?

@kevinruscoe

This comment has been minimized.

Copy link

kevinruscoe commented Mar 17, 2019

Here's a Vue version - https://gist.github.com/kevdotbadger/7dfd81d51c975156b50a717908cba891

turn your <a href="MY_PUT_URL" class="button">Go!</a> into <method-link href="MY_PUT_URL" method="PUT" classes="button">Go!</method-link>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.