5

Has anyone found a way to intercept the default Form::postLink() forms with Jquery? I would like the form to work without JS (therefore the postLink). But with JS enabled I want to intercept the post and call it via AJAX.

<?php echo $this->Form->postLink('Delete', array('action'=>'delete', $prospect['Prospect']['id']), array('class'=>'postLink', 'escape'=>false), __('Sure you want to delete # %s?', $prospect['Prospect']['id'])); ?>

generates:

<form action="/admin/prospects/delete/4f61ce95-2b6c-4009-9b89-07e852b0caef" name="post_4f648f773923b" id="post_4f648f773923b" style="display:none;" method="post">
    <input type="hidden" name="_method" value="POST"/>
</form>
<a href="#" class="postLink" onclick="if (confirm('Sure you want to delete # 4f61ce95-2b6c-4009-9b89-07e852b0caef?')) { document.post_4f648f773923b.submit(); } event.returnValue = false; return false;">
    Delete
</a>

The main problem is that the js is placed inline here. Therefore always triggers even if I try to intercept the click event (or the post event - tried that too):

<script>
$(document).ready(function() {
    $('table.list a.postLink').click(function(e) {
        e.preventDefault();
      alert('Handler for .submit() called.');
      // TODO: do ajax request here and return false
      return false;
    });
});
</script>

So in the end the form always submits normally and redirects - either ignoring any ajax call (catching the form submit) or posting/redirecting regardless of an ajax call just made (catching the click event).

I would like to delete this record via AJAX and - if successful - just remove that table row from DOM. It would be great if one doesn't have to modify all 300+ "delete buttons" in the application for it, though.

If everything fails I could probably still override the FormHelper (extend it and alias it). But I was hoping on a less invasive solution here.

mark
  • 21,691
  • 3
  • 49
  • 71

6 Answers6

8

I know this is old, but for any of those searching:

  • You need to first remove the 'onclick' attribute added to the delete link.
  • Then, you add a .click function to the delete link
  • You need the url (which can be hardcoded or retrieved from the form, which is always the prev element in cakephp Form->postLink

Here is the code:


$(function(){

    $('a:contains("Delete")').removeAttr('onclick');

    $('a:contains("Delete")').click(function(e){
        e.preventDefault();
        var form = $(this).prev();
        url = $(form).attr("action");
        $.post(url);
        return false;
    });

});
Micah Smith
  • 311
  • 2
  • 11
2

jymboche - what a genius why didnt i think of it myself?

Well, here is the modified answer of yours:

$(document).ready(function() {
    $('table.list a.postLink').removeAttr('onclick');

    $('table.list a.postLink').click(function(e) {
        e.preventDefault();
        if (!confirm('<?php echo __('Sure?')?>')) { 
            return false;
        }
        var form = $(this).prev();
        var url = $(form).attr("action");
        var tr = $(this).closest('tr');
        url = url + '.json';
        $.post(url).success(function(res) {
            if (res.error) {
                alert(res.error);
                return false;
            }
            tr.fadeOut(200);
        }).error(function() {
            alert("Error"); 
        })
        return false;
    });
});

This is for future reference only. I will still accept your answer as you gave me the right idea.

mark
  • 21,691
  • 3
  • 49
  • 71
1

jymboche's solution helped me to get to a working answer, but it didn't work fully for me, due to some security cake plugins that I have installed.

Here's what worked for me:

    $(function(){

    $('a:contains("Delete")').removeAttr('onclick');

    $('a:contains("Delete")').click(function(e){

        e.preventDefault();
        var form = $(this).prev();
        var url = $(form).attr("action");

        $.ajax({
            type: 'POST',
            cache: false,
            url: url,
            data: $(form).serialize(),
            success: function(msg) {
                // do any extra calls you need to refresh the page
            }
        });
        return false;
    });

});
Ben Hitchcock
  • 1,368
  • 10
  • 12
0

Couple of issues with the current solutions...

First and foremost, the postLink method requires Javascript to be enabled. From Cake's doco: "Creates an HTML link, but access the url using method POST. Requires javascript to be enabled in browser."

If javascript is disabled, you just get the exact same output - a hidden form, and a link that tries to submit that form with Javascript (but fails, since JS is turned off).

Second, although it will work, it seems weird to use the postLink method, and then use Javacript to undo precisely all the magic that the postLink method creates.

If you want a non-javascript friendly solution, all you have to do is create a regular form that points to the delete method, and put a link below it like this:

<?php echo $this->Form->create('DefaultAvailability', array('url' array('action' => 'delete', $myRecord['ModelName']['id'])));?>
<?php echo $this->Form->end('Delete (no JS)');?>
<a href='#'>Delete (With JS, use AJAX)</a>

Then, for cases when there's no javascript, hide the link below, and the form will work as normal.

For cases when there is javascript, hide the form, and use javascript to make your delete link trigger a submit on your delete form, and handle that submit with ajax.

joshua.paling
  • 13,762
  • 4
  • 45
  • 60
0

I've translated the previous jQuery version to Mootools

//We start with foreach, to select all ajax buttons on the page $$('.ajaxbutton').each(function(item,index){

        //remove onClick
        item.removeProperty('onclick');

        //attach click event
        item.addEvent('click', function(e){
            //stop click (in my case the form is inside another link)
            e.stop();
            var form = item.getPrevious();
            url = form.get('action');

            new Request({
                url: url,//url
                method: 'post',//method
                onSuccess: function(responseText){
                    //This is not required, we are dimming the button on success
                    item.getParents()[0].tween('opacity',0.5)
                }
            }).send();
            return false;
        });

    })
mate.gvo
  • 1,093
  • 14
  • 20
0

Just an idea, haven't tested it:

<?php echo $this->Form->postLink('Delete', array('action'=>'delete', $prospect['Prospect']['id']), array('class'=>'postLink', 'onclick' => false, 'escape'=>false), __('Sure you want to delete # %s?', $prospect['Prospect']['id'])); ?>
floriank
  • 25,546
  • 9
  • 42
  • 66
  • but then I would have to alter all 300+ views where those links occur :) I probably have to use my own form helper here which overwrites the js it outputs inline... – mark Mar 20 '12 at 15:43
  • 1
    I just tested this. It doesn't work. The onclick event still gets added. – joshua.paling Jun 04 '13 at 08:33