Hi, I agree with Igor. Just have to take care that binding to document is not a default behavior for all bound events, and that it should be use with care. (IMHO, the javadoc should be enough) Martin, I unfortunately did not had the chance to have a look at your code now... :s But, if it not the case, if think EventDelegatingBehavior should have a constructor that take a component (the datatable for instance) as an argument so the event can be bound it it instead of the document (by getting its markupid as the selector)...
[quote] Here is another important tips "*Attaching many delegated event handlers near the top of the document tree can degrade performance*". For best performance, attach delegated events at a document location as close as possible to the target elements as done in above jQuery code [/quote] http://jquerybyexample.blogspot.com/2013/04/direct-vs-delegated-events-with-jquery-on-method.html I think events delegation would be a great addition anyhow... Best regards, Sebastien. On Tue, Jul 30, 2013 at 7:07 PM, Igor Vaynberg <[email protected]>wrote: > binding on document is fine, you just have to make sure your code is fast > in case you are binding to things like mousemove. > > -igor > > > On Tue, Jul 30, 2013 at 1:31 AM, Martin Grigorov <[email protected] > >wrote: > > > On Fri, Jul 12, 2013 at 5:21 PM, Igor Vaynberg <[email protected] > > >wrote: > > > > > On Fri, Jul 12, 2013 at 1:50 AM, Martin Grigorov <[email protected] > > > > > wrote: > > > > On Fri, Jul 12, 2013 at 8:59 AM, Igor Vaynberg < > > [email protected] > > > >wrote: > > > > > > > >> On Thu, Jul 11, 2013 at 7:22 AM, Martin Grigorov < > > [email protected]> > > > >> wrote: > > > >> > On Thu, Jul 11, 2013 at 4:48 PM, Sven Meier <[email protected]> > > 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. > > > >> > > > > >> > 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. > > > >> > > > >> > > > >> this is partially on the right track, but there are still some > > > >> optimization that can be made. > > > >> > > > >> first, the ajax attributes need to be moved into a data attribute > that > > > >> is written out on the tag. the final output of attaching a onclick > > > >> ajax behavior to a tag should end up looking like this: > > > >> > > > >> <a wicket:id="ajaxlink" > > > >> data-w-click="u/?0.foo:bar.ILinkListener/c/default/pd/true"/> > > > >> > > > >> (we will need to figure out how to encode ajax attributes into a > > string) > > > >> > > > > > > > > example: > > > > <a id="c23" data-w-attrs='{"u":"someUrl","m":"post"}' ...> > > > > > > > > $('#c23').data("w-attrs") === {u: "someUrl", m: "post"} > > > > > > > > This works for valid JSON, but it doesn't for the enhancement we use > - > > > the > > > > functions for the call listeners. > > > > > > i did say we need to figure out a way to encode it right above the > > example > > > :) > > > > > > >> then you can have the one global listener: > > > >> > > > >> $(document).on("click", function(e) { > > > >> > > > > > > > > The problem here is that using 'document' will make the things > actually > > > > slower. > > > > We need to find a simple way to be able to bind on a parent > component. > > > > In Sven's example - a table with many cells the most appropriate > > element > > > is > > > > the <table> itself. > > > > > > umm, why does it make things slower exactly? this has virtually no > > > overhead, events bubble up anyways...so where does the slowness come > > > from? > > > > > > > All the talks about the deprecation of jQuery#live() say that binding on > > the document is not a good idea (performance wise). > > > > If it is not possible to bind on a context element then I see no much > > benefit. > > > > > > > > > > -igor > > > > > > > > > > > In event-delegating-behavior branch I need to traverse the parent > > > > components and their behaviors to be able to find the appropriate > > parent. > > > > So we win some performance in JS execution but lose some in Java :-/ > > > > > > > > var element=$(this), attrs=element.attr("data-w-click"); > > > >> if (attrs&&!e.handledByWicket) > > > >> Wicket.Ajax.call(attrs); > > > >> e.handledByWicket=true; // if there are more handlers above, > do > > > >> not double process the event - read below > > > >> } > > > >> } > > > >> > > > >> the advantage here is that we only have one javascript listener that > > > >> needs to be registered. > > > >> > > > >> however, there are a few disadvantages: > > > >> * event propagation options wont work anymore, because the event has > > > >> to propagate all the way to the document in order to trigger. > > > >> * some libraries block events. for example if there is a panel with > an > > > >> ajax link inside a third party modal window. the modal window lib > may > > > >> prevent any clicks from propagating out of itself, which means the > > > >> handler on the document will never see them. > > > >> > > > >> we can sort of solve this by having a behavior that would write out > > > >> the listener above, but attached to the component not the document. > > > >> > > > >> that way, if we look at my example with the panel inside the modal, > > > >> the user can add this behavior to the panel that will be in the > modal > > > >> and still be able to capture the event. > > > >> > > > >> this does, however, make troubleshooting more difficult. why didnt > my > > > >> ajax event trigger? you will have to be a lot more aware about what > > > >> javascript you have in the dom. > > > > > > > > > > > >> i think a short term goal might be to move the ajax attributes into > a > > > >> dom attribute and change our ajax code to simply say > > > >> Wicket.Ajax.bind("click", "component234"); > > > >> > > > > > > > > see above (valid JSON) > > > > > > > > we can enrich the DOM: > > > > <a ... onsuccess="someScript"> > > > > but I think this is a step back to Wicket 1.5 days (ajax decorators > on > > > > strings, etc.) > > > > > > > > > > > >> > > > >> this will register the listener like above on the element directly. > so > > > >> no delegation yet but cleaner javascript/html. also the browser > doesnt > > > >> have to parse as much javascript, so it will be a bit speedier. > > > >> > > > >> potentially we can collect ids to further optimize js size: > > > >> Wicket.Ajax.bind({click, ["c34", "c32"], blur: ["c22","c98"]); > > > >> > > > >> -igor > > > >> > > > >> > > > >> > > > > >> > > > > >> >> > > > >> >> > > > >> >> Sven > > > >> >> > > > >> >> > > > >> >> > > > >> >> On 07/11/2013 03:40 PM, Martin Grigorov wrote: > > > >> >> > > > >> >>> On Thu, Jul 11, 2013 at 4:30 PM, Nick Pratt <[email protected]> > > > 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 < > > > >> [email protected] > > > >> >>>> > > > >> >>>>> 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! > > > >> >>>>> > > > >> >>>>> > > > >> >> > > > >> > > > > > >
