patch building upon #684846: AJAX triggered by non-submit element fails if any elements are validated to trigger a form submit with a link

Marking as needs work till this patch is in.

CommentFileSizeAuthor
#3 ajax_js.patch915 bytesfago
trigger_link.patch891 bytesfago
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rfay’s picture

rfay’s picture

Issue tags: +Ajax
fago’s picture

FileSize
915 bytes

cool, thanks! I improved the comments and re-rolled the patch.

effulgentsia’s picture

This seems really cool to me, so I'm tentatively +1, but I don't have much experience with real world use-cases of triggering AJAX from links. Any chance of getting merlinofchaos to review this? Or someone else who can speak to what this solves and if any unwanted side effects are foreseen.

rfay’s picture

Isn't triggering a POST with a link considered inappropriate? Or am I missing the use case here?

The base idea, of course, is that a GET should never change anything or take any action, and links are generally associated with GETs, and buttons with POSTs.

Anyway, best to clarify the use case here.

fago’s picture

For an example use case check out the UI of http://drupal.org/node/660108 - I use it already there.

The link is used to trigger form submission instead of a button - pretty easy with the #trigger_as functionality now. The button triggers a form rebuild, but without this patch the browser won't submit the form values, thus the form looses its values.

In my use case the link triggers an AJAX callback to replace parts of the form - actually to switch between two configuration modes. Having buttons for that would clutter the form too much, thus for the JS enabled version it uses the link.

This patch doesn't change whether the AJAX request uses POST or GET at all (it's using a POST afaik), but what it changes is, that if the link is inside a form, it properly submits the form values.

fago’s picture

I do think this one is pretty straight-forward fix. It doesn't change whether links are using GET or POST requests, it just makes POST requests work properly. As of now a link used with #ajax would use POST but it wouldn't submit any form data. This patch fixes that in case the link is used in a form.

@use-case:
I'm using it together with the ajax #trigger_as functionality, so there is a button + a link. But when JS enabled, the button gets hidden and the link is shown instead. So UX is better (you won't have hundreds of buttons), but the form still degrades properly.

sun’s picture

Title: fix triggering a form submit with a link » Impossible to trigger form submit with a link
Category: task » bug
Status: Needs review » Reviewed & tested by the community

Thanks, looks good.

sun’s picture

Status: Reviewed & tested by the community » Needs work

Reconsidered. This patch will prevent #type link with #ajax from working, if there is a form nearby the ajaxified link.

Why can't you simply use #ajax[selector] instead?

fago’s picture

As of now I'm using it like this:

      $form['link'] = array(
        '#type' => 'link',
        '#href' => '#',
        '#title' => $value,
        // #id is used by the #ajax code.
        '#id' => $link_id,
        // Needed to actually output the #id.
        '#options' => array('attributes' => array('id' => $link_id)),
        '#process' => array('ajax_process_form'),
        // Hide the link by default and unhide it by javascript.
        '#prefix' => '<div class="rules-show-js">',
        '#suffix' => '</div>',
        '#ajax' => array(
          'callback' => 'rules_ui_form_ajax_reload_form',
          'wrapper' => 'rules-form-wrapper',
          'event' => 'click',
          // Trigger as the Switch button.
          'trigger_as' => array(
            'name' => 'param_' . $name,
            'value' => t('Switch'),
          ),
        ),
      );

@problem:
Do you mean #647228: Links are needlessly unable to fully participate in D7 AJAX framework features ? I don't see what should be conflicting here, so what's the problem?

@selector:
Interesting idea, I'll have a look at that. Thanks.

fago’s picture

I don't think using another element + setting a selector helps as the problem is on the js side :( - once the link is clicked still the js won't sent the form data without a patch like #3.

kvvnn’s picture

*wrong thread*

fago’s picture

As I noted in my initial post, this patch builds upon this work. Though the javascript needs this little fix to work with links too as input elements have the .form element in JS, but links do not.

BenK’s picture

Subscribing...

fago’s picture

Status: Needs work » Needs review

ok, regardless #647228: Links are needlessly unable to fully participate in D7 AJAX framework features gets in or not - this js fix is an absolute requirement in order to make link triggered form submits possible at all. Note that this can't break anything, even if an ajax submit from inside the form is supposed to not deal with a form the sent form data won't harm - while it's just impossible to something meaningful together with forms without it.
I'm using already a rather tricky form element to do that, but it is working. If #647228: Links are needlessly unable to fully participate in D7 AJAX framework features cleans it up the PHP side too, the better.

I make use of links to trigger form submission in the rules UI to replace parts of the form - thus currently the module requires this patch to work. So I'd really like to see this fixed.

fago’s picture

#3: ajax_js.patch queued for re-testing.

sun’s picture

+++ misc/ajax.js
@@ -110,11 +110,15 @@ Drupal.ajax = function (base, element, element_settings) {
-  // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
-  // bind AJAX to links as well.
+  // If there isn't a form, jQuery.ajax() will be used instead.
   if (this.element.form) {
     this.form = $(this.element.form);
   }
+  // Set the form for non-input elements like links. This allows triggering form
+  // submissions by those elements too.
+  else if ($(this.element).closest('form').length) {
+    this.form = $(this.element).closest('form');
+  }

The problem is that this patch will *always* trigger a form submission of the closest form when clicking on a link in a form, regardless of whether the link should actually trigger the form submission.

I.e., this behavior would be irreversible and cannot be changed.

However, both may be valid use-cases:

1) A link with arbitrary AJAX command(s) within a form (unrelated to the form submission).

2) A link within a form that should trigger a form submission.

The following crosses my mind:

a) Normally, I'd resort to simply output a form button with CSS class .link, so as to make the button just look like a link (who cares after all?)...

b) If a) is not an option, then #ajax on #type 'link' should be the solution, along with a new #ajax[form] property, which allows to specify a jQuery selector for non-input elements in a form.

Powered by Dreditor.

fago’s picture

The problem is that this patch will *always* trigger a form submission of the closest form when clicking on a link in a form, regardless of whether the link should actually trigger the form submission.

Hm, I think you are right with that. Unintentionally submitting forms could trigger unintended JS code to run, what is problematic. But isn't it the same if AJAX submits stem from an input element? E.g. when picking a select box item the user doesn't intend to submit the form either. But as of now it works that way, and JS related form submits would be executed?

Ad solutions:
a) Yes that would be possible, but I think theming it that way such that it works properly in every browser is rather hard. As I was aware of the nice trigger_as stuff of the AJAX framework, I thought it's easier to leverage that instead... Perhaps I should just switch to a compactly themed button instead.

b) The AJAX framework just totally misses the opportunity to submit the form from non-input elements. I don't think we need a new selector to enable both though, we could use the existing one, but when #ajax is configured to trigger as a form API button the framework needs to automatically submit the form. Thus the framework should be already able to distinguish it probably on the server side, and just needs to ensure the JS is doing it right (-> add a setting?).

But well, as of now the server side is form related only, so a simple patch like that would make theoretically sense. #647228: Links are needlessly unable to fully participate in D7 AJAX framework features might change that though.

yched’s picture

Linking to #796658: UI for field formatter settings, since it seems like a blocker to get Bojhan's approval.

yched’s picture

@fago : just curious about your use case - the functionality provided by your ajaxified-links cannot degrade without JS, right ?
I mean, without JS, a link is just a link, and clicking on it can only display a fresh form without keeping the form state...

[edit : to clarify - I'm wondering how this functionality could be used in #796658: UI for field formatter settings, I'm not questioning the general relevance]

fago’s picture

I'm using it together with the ajax #trigger_as functionality, so there is a button + a link. But when JS enabled, the button gets hidden and the link is shown instead. So UX is better (you won't have hundreds of buttons), but the form still degrades properly.

Hiding + showing stuff dependent on js is easy with simple css classes making use of html.js

nod_’s picture

Version: 7.x-dev » 8.x-dev
Status: Needs review » Needs work

I'd actually like to close this one since submitting a from from a link should just be done my triggering the submit event on the outer form, so unless i missed something big I don't see how this approach is better than triggering the usual form event.

Also you might want to send use-cases to #1533366: Simplify and optimize Drupal.ajax() instantiation and implementation to help out :)

nod_’s picture

Issue summary: View changes
Status: Needs work » Closed (works as designed)
Related issues: +#1533366: Simplify and optimize Drupal.ajax() instantiation and implementation

Shouldn't be possible to submit a form from a link like that. It's not what links are for.

3 years is a fair delay before closing I'd say :D