0

I'm building a plugin to submit forms with jQuery.

It needs to work with live elements, so I need to use $(document).on();

Here is an example of what I'm trying to accomplish:

$.fn.submittable = function() {
  $(document).on('submit', this, function(event) {
    event.preventDefault();
    //Do whatever
  });
};
$(document).ready(function() {
  $('.tosubmit').submittable();
});

But $(this) doesn't seem to work with .on()

if I do, $(this).submit(function(event) {}); it works fine.

Am I doing something wrong?

Palmer
  • 173
  • 9
  • You need to understand what `this` is. http://stackoverflow.com/questions/1051782/jquery-this-vs-this – Jay Blanchard May 16 '14 at 18:13
  • I have, that also didn't seem to work. – Palmer May 16 '14 at 18:15
  • @JayBlanchard I don't think that question is relevant here. In the context of a plugin, `this` is the jQuery object, not the DOM element – billyonecan May 16 '14 at 18:15
  • `$(this).submit(function(event) {});` if this works fine then use it, why looking for event delegation? – Jai May 16 '14 at 18:17
  • 1
    @Jai as a matter of principle I recommend that modern jQuery code should _always_ use `.on()` for event registration, and the appropriate `.trigger` call for event simulation. Having the same method (e.g. `.click`) do both is a recipe for confusion. – Alnitak May 16 '14 at 18:20
  • I've been thinking the same. Why do not all the functions, e.g. click, submit, hover use the .on(); functionality? – Palmer May 16 '14 at 18:22
  • I mean, the default. You have to specify `.on();` which is confusing. – Palmer May 16 '14 at 18:23
  • using `this` as the delegate target makes no sense, if you have access to `this`, why do you need delegation? – Kevin B May 19 '14 at 19:33

3 Answers3

3

The delegated version of .on requires that the selector parameter be a string, not an element (or in your case, a jQuery object, that being what this is within a jQuery plugin).

Why use delegation at all, though?

$.fn.submittable = function() {
    return this.on('submit', function(event) {
        event.preventDefault();
        ...
    });
};

and then just invoke that on your newly-loaded content after each AJAX call.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • 1
    The op said that it has to work with live elements, which supposedly is elements that are added dynamically. If so, that's why delegation is used. – Guffa May 16 '14 at 18:20
  • I'm building an AJAX web application in which most of the forms are live. Also, pretty much every form is submitted through AJAX. I found myself writing a function for every form. This is so all I need to do to "AJAX" a form, is add a class and call the plugin. – Palmer May 16 '14 at 18:21
  • @Guffa I missed the "live" part, but IMHO no plugin should automatically attach itself to elements not yet created. When the elements are created (which must surely be under the programmer's control) then the plugin should be invoked. – Alnitak May 16 '14 at 18:23
  • @Guffa the corollary of that is that if the plugin is not specific to a particular element then perhaps it shouldn't be a `$.fn` plugin at all. – Alnitak May 16 '14 at 18:26
  • I spoke too soon, when the form is on a page loaded with jQuery, through `.post();`, this does not work. What exactly is going on. – Palmer May 16 '14 at 19:03
1

Use the selector property to get the selector that was used to create the jQuery object:

$.fn.submittable = function() {
  $(document).on('submit', this.selector, function(event) {
    event.preventDefault();
    //Do whatever
  });
};

Note: This makes your plugin work in the way that the jQuery live method did. That way of binding events was abandoned because the syntax is a bit awkward and can cause confusion. You should consider using a syntax more like the one the on method uses for delegation:

$.fn.submittable = function(selector) {
  this.on('submit', selector, function(event) {
    event.preventDefault();
    //Do whatever
  });
};

Usage example:

$(document).submittable('.tosubmit');
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • `.selector` was deprecated in jQuery 1.7 ! – Alnitak May 16 '14 at 18:21
  • @Alnitak: That doesn't mean that it's gone. Anyhow, I also added an alternative syntax that doesn't use the `selector` property. – Guffa May 16 '14 at 18:23
  • I see your reasoning in using selector as a variable, and that does work. However I am not keen on using a plugin this way, I would rather do `$('.tosubmit').submittable();` Is there a way to do that with this method? – Palmer May 16 '14 at 19:09
  • @Palmer: No, then you need to use the first approach. If you want to specify the selector by creating a jQuery object with it, then you have to dig the selector out of the jQuery object. – Guffa May 16 '14 at 19:49
  • @Palmer strictly speaking you're abusing the plugin mechanism. The element on which a `$.fn.foo` is invoked must (albeit only by convention) _always_ already exist, even in a delegated `.on` call. FWIW, I'm not sure what you're trying to do would even work with a delegated call, some answers here say that on some browsers the `submit` event doesn't bubble. – Alnitak May 16 '14 at 21:25
  • How should I go about this then? – Palmer May 16 '14 at 22:13
1

I'm not sure I explained the issue well enough. The replies to this question suggested this was bad practice, and I was not sure why. However I just found the solution and all is now clear to me.

When using plugins with live content, the plugin must be loaded inside the $.post or .get function like so.

$.post('.').done(function(data) {
  $('.to-call-on').plugin();
});
Palmer
  • 173
  • 9
  • So in other words you had an X/Y problem. Instead of asking how to apply plugins to dynamic elements, you asked how to use `this` with .on for delegation, which is confusing because knowing what that syntax does makes using it that way not make sense. However, i'm glad you found the correct way of fixing it. – Kevin B May 19 '14 at 19:36
  • Yup, that's what I told you to do: _"just invoke that on your newly-loaded content after each AJAX call."_ – Alnitak May 21 '14 at 13:17
  • Ya, thanks for the help. I see now that I was an ignoramus, and should have looked closer at what you posted which was in fact so very clear. – Palmer May 21 '14 at 17:44