A modest proposal: Rather than making it possible to simply pass an Element into Widgets' ctor's, add a specialized method for creating them from an existing element's id.
The reason for this is that we have no guarantee that a raw Element object is attached to the DOM, which can lead to unpredictable behavior and memory leaks. If the interface requires that the Element be findable via $doc.getElementById(), then we *can* make this guarantee and avoid these issues altogether.
Basically, if we do this, the problem becomes much more easily tractable, with few if any error cases. Would this deal with the problems that everyone is having hooking into existing pages/forms on pages? Are there other (important) use-cases I may be missing?
It seems like we are removing the ability to subclass with this solution, which can be very useful at times.
Can you explain why we need to know if the element is attached or not? As to avoid memory leaks we currently attach and detach when the Widget is removed from its parent, how would the new system work?
so if you want to do validation on all input tags with a class name of
date, you'd first have to walk the DOM looking for the elements that
fit your criteria, then add IDs to them then search the DOM again for
those IDs.
It would be particularly handy if you could use the selectors api http://www.w3.org/TR/selectors-api/
in a factory method that would only walk the DOM once, and create
widgets with the found elements.
Collection<TextBox> dateBoxList = TextBox.selectAll("input.date");
// add validation listeners ...
With this solution, you are still guaranteeing that your elements are
attached to DOM, but at the same time you've gained quite a lot of
flexibility in identifying the elements you want to hijack.
there are already several implementations of the selectors api in
javascript, so it can't be that tough to create one for GWT. In fact,
Safari already includes a native implementation.
-jason
On Tue, Apr 15, 2008 at 11:32 AM, Emily Crutcher <e...@google.com> wrote:It seems like we are removing the ability to subclass with this solution, which can be very useful at times.How so? If I subclass one of these widgets, I can still create my own ctors that delegate both cases (by-id or default) to the super ctors. The only thing we'd be doing is formalizing the already-true assumption that these widgets use a single element type and impose no extra structure. Am I missing something here?
Can you explain why we need to know if the element is attached or not? As to avoid memory leaks we currently attach and detach when the Widget is removed from its parent, how would the new system work?
If we know the element is attached, we can simply call onAttach() directly from the ctor. If we don't, then we'll simply have to *assume* that it's attached, and if it's wrong, then some things will simply not work for obscure and hard-to-debug reasons (e.g. CheckBox and Image behave differently when detached). We'll still have to do something to ensure that onDetach() is called when the page is unloaded, though.
On Tue, Apr 15, 2008 at 11:06 AM, Joel Webber <j...@google.com> wrote:
All,The issues brought up in 1544 have been bugging people for some time, and we've put off dealing with it because it's pretty thorny in the general case.I just added the following comment to the issue:A modest proposal: Rather than making it possible to simply pass an Element into Widgets' ctor's, add a specialized method for creating them from an existing element's id.The reason for this is that we have no guarantee that a raw Element object is attached to the DOM, which can lead to unpredictable behavior and memory leaks. If the interface requires that the Element be findable via $doc.getElementById(), then we *can* make this guarantee and avoid these issues altogether.Basically, if we do this, the problem becomes much more easily tractable, with few if any error cases. Would this deal with the problems that everyone is having hooking into existing pages/forms on pages? Are there other (important) use-cases I may be missing?Side note: I do realize that we still have an issue with missing Anchor, "raw" RadioButton, and "raw" CheckBox classes that form part of this problem as well. I'm about to enter a separate issue for these cases.Thanks,joel.
--"There are only 10 types of people in the world: Those who understand binary, and those who don't"
On Tue, Apr 15, 2008 at 11:53 AM, Joel Webber <j...@google.com> wrote:On Tue, Apr 15, 2008 at 11:32 AM, Emily Crutcher <e...@google.com> wrote:It seems like we are removing the ability to subclass with this solution, which can be very useful at times.How so? If I subclass one of these widgets, I can still create my own ctors that delegate both cases (by-id or default) to the super ctors. The only thing we'd be doing is formalizing the already-true assumption that these widgets use a single element type and impose no extra structure. Am I missing something here?
I think maybe I mis-understood as when you said:
Rather than making it possible to simply pass an Element into Widgets' ctor's, add a specialized method for creating them from an existing element's id.
I interpreted "method" as a method rather than a constructor, if what you meant is add a specialized constructor for creating them from an existing element's id, I withdraw my objection.
Can you explain why we need to know if the element is attached or not? As to avoid memory leaks we currently attach and detach when the Widget is removed from its parent, how would the new system work?
If we know the element is attached, we can simply call onAttach() directly from the ctor. If we don't, then we'll simply have to *assume* that it's attached, and if it's wrong, then some things will simply not work for obscure and hard-to-debug reasons (e.g. CheckBox and Image behave differently when detached). We'll still have to do something to ensure that onDetach() is called when the page is unloaded, though.
It seems like using this algorithm once one of these widgets is introduced, there is no easy way to garbage collect its listener. I'm worried we will end up with a protocol which introduce memory leaks into our users programs without an easy way to back it out.
:)
-Ray
This is why I pointed out that we would need to be sure that onDetach() is called when the page is unloaded. This is all that is required to make sure event handlers get cleaned up and memory leaks avoided. Also, I'm not really talking about adding new widgets here (except to the extent that we will need simpler checkbox and radiobutton widgets), but just simplifying an existing use pattern that many people are already hacking their way through currently (just being able to specify the elements that are used for form-type widgets). The current use patterns are *definitely* introducing leaks.
hi Joel,
I've the exact problem:
I'm able to:
- get eleement(s) from existing html markup (no issues)
- ensure they are "attached" by calling "onAttach"
- use them as UIObject/Widget or concrete implementation (or as
elements)
I'm fail to:
- ensure that listeners are cleared
When I'm using my own implementation I'm forced to stop at point where
modifying (patching) containers is required because they adopt and
track children,
As to missing "raw" widgets:
#1
that could be limiting if we concentrate of existing GWT UI widgets
implementation. Most frequently I don't have to use GWT UI raw widget
class directly (e.g. say "Button" widget) because existing html markup
implements functionality of "button" but it is build differently:
anchor/img tags, div+backgroundImage, span+divs, anchor
+backgroundImage to name few implementation I frequently see
#2
I would really want is to be able to subclass concrete UIObject/Widget
without patching it (to access private only members/methods) that way
I could attach it to existing html markup and ALSO be able to remove/
detach such sniffed widget(s) to also sniffed implementations of Panel
class. For example DropList is build that way it cannot be sub-classed
because of access to member methods/fields implementation: I cannot
call super.checkIndex(index) because that's privet method nor I can
implement it differently. I think that partially answer Emily question
about subclassing (though in indirect way): because existing markup
can be structured a little differently then that found in GWT UI
implementation a subtle changes should be implemented in subclass,
FileUpload: <input type='file'>
Button: <button>/<input type='submit|reset'>
ListBox: <select>
TextBox: <input type='text'>
PasswordTextBox: <input type='password'>
Frame: <iframe>
Hidden: <input type='hidden'>
Image: <img>
Label: <div>/<span>
HTML: <div>/<span>
RawRadioButton (name open for debate): <input type='radio'>
RawCheckBox (ditto): <input type='checkbox'>
Link (ditto again): <a>
Note that there are no cases here where the HTML structure for the widget is debatable -- it's always exactly one element. The proposed change is also not intended to help anyone get access to provide members of superclasses. This is an entirely different problem (not to say it's not important at times, just different).
joel.
This is why I pointed out that we would need to be sure that onDetach() is called when the page is unloaded. This is all that is required to make sure event handlers get cleaned up and memory leaks avoided. Also, I'm not really talking about adding new widgets here (except to the extent that we will need simpler checkbox and radiobutton widgets), but just simplifying an existing use pattern that many people are already hacking their way through currently (just being able to specify the elements that are used for form-type widgets). The current use patterns are *definitely* introducing leaks.
What happens when your app would naturally update the widgets (For instance in a PagingGrid). When previously the widgets would be correctly cleared, won't they stay in memory forever if we attach an event listener on load?
I'm referring to widgets in a PagingGrid, not the paging grid itself.
So for example:
Client gets server-side table contents.
Client displays contents from server-side table.
Client creates widgets from elements to make the server side contents respond to events.
In this case, it seems like we'd see the sort of memory leaks that tend to make everyone have to close and restart their web-mail programs once every couple of days.
$("table#myresults td").each(new Function() {
public void exec(Element e) {
$(e).wrap(Label.class).addClickListener(...);
}
});
:) The issue is how to do it, do it fast, and not leak memory. :)
-Ray
That is some sexy looking code! Too bad Java doesn't have closures....
By the way, could you make $(String) return an Iterable<Element> so
you could do this:
for (Element e : $("table#myresults td")) {
$(e).wrap(Label.class).addClickListener(...);
}
?
Ian
--
Tired of pop-ups, security holes, and spyware?
Try Firefox: http://www.getfirefox.com
Thanks for the idea. How many people are interested in firming up all
the missing methods in GQuery and adding some comparable plugins once
I release it? :) I'm kinda busy, so I'm only going to take it as far
as CSS3 selector support and JQuery core.
-Ray