bind on document, and it was slow.
Sure, the higher you register a delegating event handler in the markup tree,
the slower it is.
The same holds for using event delegation on a table with a deeply nested cell
structure.
Sven
On 07/11/2013 04:54 PM, Martin Grigorov wrote:
On Thu, Jul 11, 2013 at 5:22 PM, Martin Grigorov <mgrigo...@apache.org>wrote:
On Thu, Jul 11, 2013 at 4:48 PM, Sven Meier <s...@meiers.net> wrote:
Hi,
The idea with plain JS solution I cannot visualize in my head yet.
EventDelegatingBehavior is just a collector of JavaScript snippets. The
actual magic runs in the browser: a custom bubbling of events and
delegation to the actual behavior.
It should be possible to do this plain with JavaScript:
public class DelegatingAjax implements IAjax {
public ajax(IHeaderResponse response, Component component,
AjaxRequestAttributes attributes) {
CharSequence ajaxAttributes = renderAjaxAttributes(**component,
attributes);
response.render(**OnDomReadyHeaderItem.**forScript("Wicket.Event.***delegate*("
+ ajaxAttributes + ");");
}
}
This would be page-global though.
This is an important detail!
I'll consult with my frontend colleagues but so far I don't see problems.
And they say this is a bad idea.
jQuery.live() (deprecated in 1.7.0) did the same, bind on document, and it
was slow.
See http://api.jquery.com/live/
Also see
http://www.ultimatewebtips.com/why-jquery-live-is-a-bad-option-to-use/
For every delegated component we can set special CSS class, e.g.
'wicket-delegated'.
The binding will be: $(document).on('click', '.wicket-delegated',
function(event) {....})
i.e. we will take advantage of jQuery delegation/live support.
This way even newly added items in the repeaters will be automatically
supported.
Sven
On 07/11/2013 03:40 PM, Martin Grigorov wrote:
On Thu, Jul 11, 2013 at 4:30 PM, Nick Pratt <nbpr...@gmail.com> wrote:
I think this is great - we have some tables now with a ton of JS events
on
the child elements. Just to clarify, will this make the rendered page
smaller since there will only be a single JS handler for the event for
the
container rather than N JS handlers?
At the moment all attributes for an inner element are preserved.
'e' (the event name), 'c' (the component markup id), pd (prevent
default),
sp (stop propagation) can be removed because they are not really used.
But every inner element can have its own call listeners, form submitters
can also have custom settings ('f', 'sc', 'mp', 'm'), so I think they
have
to be preserved.
If you look in #updateAjaxAttributes() for your ajax behaviors in your
table cells you will probably notice that they have their own attributes.
Making it switchable (I think how Sven suggested) would be an
improvement -
we could leave it off by default, but provide a simple switch on a
per-container (or per-app) basis that would allow the dev to choose.
Yes, it looks as an improvement.
Moving the current code to such implementation is easy.
The idea with plain JS solution I cannot visualize in my head yet.
Regards
Nick
On Thu, Jul 11, 2013 at 4:59 AM, Martin Grigorov <mgrigo...@apache.org
wrote:
Hi,
At https://github.com/apache/**wicket/compare/event-**
delegating-behavioryou<https://github.com/apache/wicket/compare/event-delegating-behavioryou>
may see the diff between master and event-delegating-behavior branches.
The latter provides a new AjaxEventBehavior (AEB) -
EventDelegatingBehavior
(EDB), that suppresses the JS event binding for all AjaxEventBehaviors
for
a given event type (click, submit, change, ...) in the children
components
of the host component of EDB.
How EDB works:
- until now AjaxEventBehavior#renderHead() renders ondomready header
item
with JS snippet like:
Wicket.Ajax.ajax(**attributesObject);
In the new branch there is a check if some parent has EDB for the event
type of this AEB, and if there is such then the AEB "donates" its
attributes to the EDB.
- EventDelegatingBehavior#**getCallbackScript() renders :
Wicket.Event.delegate('**edbComponentMarkupId', 'eventType',
edbAttributes,
childrenAttrsMap);
- when a delegated component fires its event (e.g. the user clicks on
an
AjaxLink) the event is handled by EDB's event handler. It extracts the
markupId of the inner HTML element and fires Wicket.Ajax.Call with the
specific attributes for the extracted inner element.
Pros:
- simple to use - just add EDB to a container component around your
Ajax
heavy component (e.g. repeater with many Ajax behaviors). See the demo
app
at
https://issues.apache.org/**jira/browse/WICKET-5267<https://issues.apache.org/jira/browse/WICKET-5267>
- faster JS execution
-- faster execution of the domready handler because there is just one
binding instead of N
-- faster reaction because the browser finds the event handler much
faster.
I wasn't able to prove this with numbers because there is no way to
detect
the 'start time', i.e. when the user makes the action. With JS the
earliest
point is when the browser has already looked up the event handler.
Chrome Dev tools (timeline, profiling, pagespeed) don't help too. So my
reference that it is faster are the articles in the web and a use case
in
our application.
Cons:
- AEB#renderHead() needs to check whether there is EDB up in the
hierarchy
to be able to decide what to do.
This is ugly, I agree. But I see no other solution that will preserve
the
transparent usage of something like EDB and will not require a major
rewrite of user applications to be able to use event delegation.
-- there are some optimizations to lower the impact of the new checks:
--- a new setting (IAjaxSettings#**useEventDelegation) - a global
property
that prevents visiting the parent components and their behaviors for
all
apps which do not use EDB
--- when EDB is bound it registers a metadata for its event type in the
page instance. This prevents visiting all behaviors of all parent
components
I have no more ideas how to further optimize it.
Any feedback is welcome! Even if you have a completely different idea
how
to implement this functionality.
Thanks for reading!