Nice solution Ben 😊
We found that we couldn’t visual style a submit input button to give feedback
that the request was being processed so instead created a mixin that when the
submit button was clicked, it was converted into a link that could then be
styled with a spinner and visually disabled. It is a very hacky solution so
happy to see alternative solutions especially with a submit input button.
DisableAfterSubmit.java
import org.apache.tapestry5.ClientElement;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.InjectContainer;
import org.apache.tapestry5.annotations.MixinAfter;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
@MixinAfter
public class DisableAfterSubmit
{
@InjectContainer private ClientElement element;
@Environmental private JavaScriptSupport javaScriptSupport;
void afterRender() {
final JSONObject spec = new JSONObject();
spec.put("elementId", element.getClientId());
javaScriptSupport.require("pqc/mixins/DisableAfterSubmit").invoke("initialize").with(spec);
}
}
DisableAfterSubmit.js
(function() {
define(["jquery"], function($j) {
var initialize = function(spec) {
$j('#' + spec.elementId).on('click', spec, afterClick);
};
var afterClick = function(event) {
// AJAX submit hack: to allow a spinner to be positioned by
changing from an input[type=submit] to an anchor element
// (as Tapestry form submissions via AJAX do not work now
except through an input[type=submit])
var originalElement = $j('#' + event.data.elementId);
var attrs = {'href':'#'};
var valueAttr;
var idAttr = 'hack';
$j.each(originalElement[0].attributes, function(index, attr) {
if (attr.nodeName === 'type') {
// No need to add type=submit so continue
return;
}
if (attr.nodeName === 'value') {
valueAttr = attr.nodeValue;
return;
}
if (attr.nodeName === 'id') {
attrs[attr.nodeName] = attr.nodeValue + idAttr;
return;
}
attrs[attr.nodeName] = attr.nodeValue;
});
originalElement.hide();
originalElement.after(function () {
return $j('<a/>', attrs).append(valueAttr);
});
$j('#' + event.data.elementId + idAttr).addClass('disabled
spinner').attr({'role':'alert', 'aria-busy':'true'}).focus();
};
return {
initialize : initialize
};
});
}).call(this);
Cheers,
Niran
PS:
I’m sorry if you receive this email twice as I used different email domain for
subscribing to this list and I didn’t see that initial email come through. I
have now subscribed using this email address..
From: Ben Weidig <[email protected]>
Date: Sunday, 26 February 2023 at 14:22
To: Tapestry users <[email protected]>
Subject: Re: Preventing double click eventlink and form submit
Hi Nathan,
Maybe I misunderstood your goal, but I would solve it with a module
configured by CSS classes or data attributes instead of dedicated
components.
Something along the line of this (untested) CoffeeScript I improvised:
define ['jquery', 't5/core/events'], ($, events) ->
EVENT = 'click.request-in-progress'
register = ->
$('.show-request-in-progress').off(EVENT).on EVENT, ->
$el = $(this)
$el.addClass('request-in-progress')
relatedZone = $el.data('target-zone')
elEvent = "#{t5events.zone.wilUpdate}.##{$el.id}"
zone.on elEvent, ->
zone.off(elEvent)
trigger.removeClass('request-in-progress')
return true
$ ->
register()
$(document).on events.zone.didUpdate, register
See
https://urldefense.com/v3/__https://gist.github.com/benweidig/2f2fdb32c74cbd57764b1f7dabbe7079__;!!NknhfzgzgQ!yowXeuZLQZ1AaayarMGyXEXL1HzNLMBuDQXODpgTaFvtxz2t3os3D2bD6FeSb24bEnUMv9tTOwG6dX3IZPu215m5$<https://urldefense.com/v3/__https:/gist.github.com/benweidig/2f2fdb32c74cbd57764b1f7dabbe7079__;!!NknhfzgzgQ!yowXeuZLQZ1AaayarMGyXEXL1HzNLMBuDQXODpgTaFvtxz2t3os3D2bD6FeSb24bEnUMv9tTOwG6dX3IZPu215m5$>
for
a nicely formatted version.
This way, you wouldn't need an additional zone and just need to listen to
the content zone to be updated. Only the ".show-request-in-progress" and
"data-target-zone" must be set accordingly.
Actually, the CSS classes isn't needed and the relevant elements could be
targeted via the data attribute.
Cheers
Ben
On Fri, Feb 24, 2023 at 2:11 PM Nathan Quirynen <[email protected]>
wrote:
> Hi,
>
> I am looking for a solution to prevent multiple clicks on event links or
> form submits in our Tapestry application and in the meanwhile if
> possible giving the user visual feedback while the request is being
> processed.
> We use ajax (async="true") on both our eventlinks and form components,
> but there are no javascript events to hook into right before the request
> is fired and when the request response is handled. But after some
> research I found I can use the zone parameter instead of the async
> parameter and then make use of the t5:zone:refresh and
> t5:zone:did-update events to do exactly that.
> So I came up with following javascript module which can be used for both
> form submit buttons and eventlinks:
>
> var init = function(triggerClientId, zoneClientId) {
>
> var trigger = $('#' + triggerClientId);
> var zone = $('#' + zoneClientId);
>
> var event_request = 't5:zone:refresh' + '.' +
> triggerClientId;
>
> zone.on(event_request, function(e) {
>
> // disable trigger + add css class
> trigger.css('pointer-events', 'none');
> trigger.addClass('request-in-progress');
>
> var event_response = 't5:zone:did-update' + '.' +
> triggerClientId;
> zone.on(event_response, function() {
>
> // remove response event handler
> zone.off(event_response);
>
> // reenable trigger + remove css class
> trigger.css('pointer-events', 'auto');
> trigger.removeClass('request-in-progress');
>
> });
> });
>
> }
>
> I would make new components AjaxForm/AjaxEventLink to wrap the original
> ones and implement everything there.
> This seems to work as I hoped it would be, but then a zone element is
> added for every EventLink/Form which seems a bit like overkill, but I
> don't see another way at the moment.
> I was wondering if others have tried to do something like I am, or if
> there's any better way of achieving what I am trying here? Or anything
> that I am missing could be wrong with my implementation?
>
>
> Nathan
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
>
Confidentiality note: This e-mail may contain confidential information from
Clarivate. If you are not the intended recipient, be aware that any disclosure,
copying, distribution or use of the contents of this e-mail is strictly
prohibited. If you have received this e-mail in error, please delete this
e-mail and notify the sender immediately.