rails / jquery-ujs

Ruby on Rails unobtrusive scripting adapter for jQuery
MIT License
2.6k stars 508 forks source link

Changing ajax:complete delegation. #394

Open baxang opened 9 years ago

baxang commented 9 years ago

Hi,

I have a remote form and want to leave the submit button disabled if the submission has succeeded while keep the original behaviour when failed.

I came up with loading this patch after jquery_ujs.js as https://github.com/rails/jquery-ujs/blob/master/src/rails.js#L460:L462 doesn't seem to allow me to override/change the default behaviour in a neat way :

(function($, undefined) {
  var $document = $(document);
  $document.undelegate($.rails.formSubmitSelector, 'ajax:complete.rails');
  $document.delegate($.rails.formSubmitSelector, 'ajax:error.rails', function(event) {
    if (this == event.target) $.rails.enableFormElements($(this));
  });
})(jQuery);

Is there a better way to do it? Otherwise it would be great if it's customizable.

lucasmazza commented 9 years ago

Have you tried to disable it again on the success callback? Sounds reasonable enough for me to do this in such case.

baxang commented 9 years ago

Thank you for the suggestion @lucasmazza, but I think I can't rely on that because an ajax:complete is triggered after ajax:success or ajax:error events. The button still is disabled.

JangoSteve commented 9 years ago

@baxang It is customizable! The event binding is namespaced precisely so you can undelegate specific event bindings as needed, just as you've done here. So this is indeed a great way to do it. I'm not really sure what you have in mind in terms of overriding/changing behavior in a neat way.

As usual though there are other ways you could accomplish the same thing as well. You could do what @lucasmazza is suggesting by checking for success in the ajax:complete event:

$(document).delegate($.rails.formSubmitSelector, 'ajax:complete', function(event) {
  if (this == event.target && (status >= 200 && status < 300 || status === 304)) rails.disableFormElements($(this));
});

That takes your 5 lines down to 3 lines. Not sure if it's ideal or not, given that it would be enabled and then re-disabled quickly, or if it would even matter or be noticeable.

You could also try modifying the enableSelector or something like that, but I haven't really thought through how that could work for your situation.

baxang commented 9 years ago

Thanks for the help. I'm glad to here my approach wasn't that bad. And I think your suggestion does the job too.

I've been thinking about what I ambiguously stated override/customize.

Just wrapping up my situation: I have a remote form that our website visitors can leave their contact information so we can call them later. The form uses ajax calls because I want to validate user input both the client and server-side without a page move. Once form submission has succeeded, the form's ajax:success callback executes location.href = data.path which has been returned from the server.

In this case re-enabling form elements after a successful request can confuse site visitors if the page move is not done as fast as the user cannot notice the delay and the user might try to submit the form again resulting duplications.

I was thinking if we can add a data-something option on form tag to control whether the form elements will be re-enabled or not per returned status(es). For instance <form data-enable-on="complete|error" ..>.

What do you think?

arg commented 9 years ago

:+1: for the approach from the comment above. We ran into the same problem. First we used a workaround:

$(this).find('button[type="submit"]').removeAttr('data-disable-with')

This code, added to the ajax:success callback, removes the data-disable-with attribute from the "Submit" button. As a result the button will remain disabled since $.rails.enableSelector query won't match it.

Later we decided to add a custom data-attribute that contains statuses (success, error) in which the submit button will be enabled on ajax:complete. It's similar to the mentioned above and I can open a pull request if you approve this solution.