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.

muffycompo commented Mar 7, 2013

Nice one Jeffrey, Thanks!

@ericlbarnes

This comment has been minimized.

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.

Owner

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.

tommymarshall commented Mar 8, 2013

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

@alexrussell

This comment has been minimized.

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.

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.

franzose commented Mar 22, 2014

Thanks!

@gpai

This comment has been minimized.

gpai commented Apr 30, 2014

Thanks a bunch! This helped so much!

@cmd0315

This comment has been minimized.

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.

cavalor commented Aug 23, 2014

thanks!!! that helped me so much.

@dlm423

This comment has been minimized.

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.

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.

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.

lexdevelop commented Mar 3, 2015

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

@rattfieldnz

This comment has been minimized.

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.

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.

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.

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.

soufianeEL commented Jun 4, 2015

updated to larevel 5
here

@tahertechs

This comment has been minimized.

tahertechs commented Jul 10, 2015

You are genious.

@jeimz143

This comment has been minimized.

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.

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.

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.

Chalkin commented Feb 1, 2016

Thanks a lot guys! Works perfectly and saves lives!

@junkystu

This comment has been minimized.

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.

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.

alimranahmed commented May 11, 2016

^^
Thanks @dialyy

@neoplomero

This comment has been minimized.

neoplomero commented May 14, 2016

@dialyy +1

@pastullo

This comment has been minimized.

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.

MevlutOzdemir commented Oct 4, 2016

Thanks @dialyy !!!

@ghost

This comment has been minimized.

ghost commented Oct 8, 2016

Thx @dially

@jeffochoa

This comment has been minimized.

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.

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.

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.

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.

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.

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.

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.

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment