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!
> > > >> >>>>>
> > > >> >>>>>
> > > >> >>
> > > >>
> > >
> >
>

Reply via email to