> Thanks for reading!
How about making the whole thing a little more 'pluggable'?
// AjaxEventBehavior
public void renderHead(final Component component, final
IHeaderResponse response)
{
super.renderHead(component, response);
if (component.isEnabledInHierarchy())
{
component.getApplication().getJavaScriptLibrarySettings().getAjax().ajax(response,
component, getAttributes());
}
}
public class DefaultAjax implements IAjax {
public ajax(IHeaderResponse response, Component component,
AjaxRequestAttributes attributes) {
CharSequence ajaxAttributes = renderAjaxAttributes(component,
attributes);
response.render(OnDomReadyHeaderItem.forScript("Wicket.Ajax.ajax(" +
ajaxAttributes + ");");
}
}
Then an alternative implementation could do as much delegation as it
wants to. For example we could build a pure JavaScript solution that
works without an EventDelegatingBehavior.
Sven
On 07/11/2013 10:59 AM, Martin Grigorov wrote:
Hi,
At https://github.com/apache/wicket/compare/event-delegating-behavior you
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
- 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!