I have written a data binding framework for myself that I think could
be generally useful. I am currently busy documenting it, and soon
(hopefully in the next business day or two) I intend to post it here
for review. I'm very excited by the ease of use I have managed to
extract from my library and I hope it can help others, too. Perhaps
the most exciting single feature is @Calculate, demonstrated here:
public interface PersonForm extends Form<Person> {
Field<Person, String> getFirstName();
Field<Person, String> getLastName();
@Calculate("${firstName} + \" \" + ${lastName}")
Formula<Person, String> getFullName();
}
// in widget code:
PersonForm form = GWT.create(PersonForm.class);
Person me = new Person("Ian", "Petersen");
BoundForm<Person> boundForm = form.bindTo(me);
BoundField<Person, String> firstName = boundForm.bind(form.getFirstName());
BoundField<Person, String> lastName = boundForm.bind(form.getLastName());
BoundFormula<Person, String> fullName = boundForm.bind(form.getFullName());
Grid grid = new Grid(3, 2);
grid.setWidget(0, 0, firstName.getLabel());
grid.setWidget(0, 1, firstName.getEditor().asWidget());
grid.setWidget(1, 0, lastName.getLabel());
grid.setWidget(1, 1, lastName.getEditor().asWidget());
grid.setWidget(2, 0, fullName.getLabel());
grid.setWidget(2, 1, fullName.getViewer().asWidget());
The result is a 2 x 3 grid. The left-most cells will contain labels
for the right-most cells. The two calls to getEditor().asWidget()
result in text boxes that can edit the first- and last-name fields,
respectively. The exciting bit (for me) is that the Viewer created
for the last cell will automatically update itself as the user changes
the values in the text boxes. The magic mostly happens in a generator
and @Calculate can accept just about any Java expression that you can
cram between a return and a ;.
Ian
I'm kind torn between Guice-like Java bindings, and using a DSL. I had
extensive experience on XForms as part of the W3C working group, and
I'm kinda partial to the declarative approach, especially since they
are many nice things you can do with validation, dependencies, and
computed properties. On the other hand, Guice-like syntax leverages
your IDE tool chain and familiarity with the Java language, but I tend
to think that really complex bindings start to become unreadable with
too much synax. Guice like syntax tends to make avoiding String
literals hard without hacks like type-safe delegates.
Without data binding, and simple HasData interface, we'd have something like:
public class Contact {
public String getFirstName();
public String getLastName();
}
public class ContactForm extends Composite implements HasData<Contact> {
public void setData(Contact c) { ... }
public Contact getData() { ... }
}
but this has a few problems. 1) Sometimes you don't control the Widget
or the Widget has a different data model, and you want to map Contact
fields into the Widget's data model (perhaps it implements
HasData<Person> instead of HasData<Contact>) 2) You can't have more
than one implements HasData, and there might be aggregation scenarios
where a widget operates on more than one data model.
So I tend to view a more general purpose data binding framework with
high granularity as being more valuable for code reuse and gluing lots
of stuff together than something like the HasData approach.
> public interface PersonForm extends Form<Person> {
>
> Field<Person, String> getFirstName();
>
> Field<Person, String> getLastName();
>
> @Calculate("${firstName} + \" \" + ${lastName}")
> Formula<Person, String> getFullName();
> }
What is the second type parameter and why is it needed? I get that
the first parameter probably allows the generator to go introspect the
Person type and find an identically named method getFirstName(), is
the second parameter supposed to represent the return type of the
Person.getFirstName() method?
> // in widget code:
> PersonForm form = GWT.create(PersonForm.class);
>
> Person me = new Person("Ian", "Petersen");
>
> BoundForm<Person> boundForm = form.bindTo(me);
>
> BoundField<Person, String> firstName = boundForm.bind(form.getFirstName());
> BoundField<Person, String> lastName = boundForm.bind(form.getLastName());
> BoundFormula<Person, String> fullName = boundForm.bind(form.getFullName());
>
Is there any way we can make the actual binding declarations more
succinct? This seems awfully verbose and repetitive.
> The exciting bit (for me) is that the Viewer created
> for the last cell will automatically update itself as the user changes
> the values in the text boxes. The magic mostly happens in a generator
> and @Calculate can accept just about any Java expression that you can
> cram between a return and a ;.
This can be tricky. In order to make this work correctly, you're
going to have to implement a master-dependency graph and evaluate
@Calculates according to topological sort order. This is how it's done
in spreadsheets and in XForms. If not, and if @Calculate expressions
reference other formulas, you can end up with inconsistent results.
You can also detect infinite loops as well (A = B + 1, B = A + 1) and
warn people about them.
All in all, I think it looks good, but I'm not totally happy with the
generic type verbosity required. I give you props for avoiding dynamic
runtime introspection, and you proposal should allow for very
efficient binding expressions to be generated by the compiler while
minimally impacting pruning and type tightening.
I'm somewhat confused about how data fields magically turn into
Widgets. How do I say something is a Radio button, or a
CreditCardEntryWidget?
-Ray
>
> Ian
>
> >
>
Yes, the second type parameter represents the property type. It's
needed to keep the whole system as tightly-typed as possible. The
compiled output surprised me with its efficiency. This data binding
library has been factored out of a larger project and, on and off,
I've been struggling with how to do data binding for a couple of years
now. Previous attempts have been slow and ungainly. This attempt
seems to be pretty tight after the GWT compiler has its way with it.
> Is there any way we can make the actual binding declarations more
> succinct? This seems awfully verbose and repetitive.
As far as I can tell, the verbosity is this library's biggest
downside, and I'm not sure how to improve it. I'm hoping that
releasing it publicly will bring in some new eyes and maybe it can be
fixed.
> This can be tricky. In order to make this work correctly, you're
> going to have to implement a master-dependency graph and evaluate
> @Calculates according to topological sort order. This is how it's done
> in spreadsheets and in XForms. If not, and if @Calculate expressions
> reference other formulas, you can end up with inconsistent results.
> You can also detect infinite loops as well (A = B + 1, B = A + 1) and
> warn people about them.
In its current state, @Calculate can only refer to properties of the
underlying bean type--not to other fields or formulae in the same
form, so cycles are impossible. It would be nice, though, to do as
you suggest because it would make certain @Calculate declarations less
verbose.
(In my project, I have a type PaperDimension with properties cwtPrice,
MWeight, and markup. There are two calculated fields: costPerM and
chargePerM. costPerM is declared like this:
@Calculate("${cwtPrice} * ${MWeight} / 100")
and chargePerM is declared like this:
@Calculate("${cwtPrice} * ${MWeight} / 100 * (1.0 + ${markup})")
It would be nice for chargePerM to be dependent on costPerM so the
declaration could be simplified to this:
@Calculate("${costPerM} * (1.0 + ${markup})")
but it was too complicated for a first pass.)
> All in all, I think it looks good, but I'm not totally happy with the
> generic type verbosity required. I give you props for avoiding dynamic
> runtime introspection, and you proposal should allow for very
> efficient binding expressions to be generated by the compiler while
> minimally impacting pruning and type tightening.
Wow! Props from Ray Cromwell of all people. I should get those framed.
Anyway, I agree, the verbosity is high. I'm not sure how to reduce
it. Maybe I should post the source immediately and repost it with
documentation ASAP.
> I'm somewhat confused about how data fields magically turn into
> Widgets. How do I say something is a Radio button, or a
> CreditCardEntryWidget?
The generator makes a bunch of assumptions to keep verbosity down in
the Form declaration, but you can override the assumptions with
annotations. By default, Boolean values are both displayed and edited
in a SimpleCheckBox. All other types are displayed in Labels and
edited in TextBoxes. To smooth over the various possible widget
interfaces, I defined the following two interfaces:
public interface Viewer<T> {
/**
* Returns {@code this}.
*/
Widget asWidget();
void display(T value);
}
public interface Editor<T> extends Viewer<T> {
T readValue();
void addChangeListener(EditorChangeListener<? super T> listener);
void removeChangeListener(EditorChangeListener<? super T> listener);
}
If you want to use a non-default editor or viewer, you can annotate
the Field/Formula declaration with @UseEditor or @UseViewer:
@Target(METHOD)
public @interface UseEditor {
Class<? extends Editor> value();
/**
* Some arguments to pass to the editor's constructor. Pasted into
the generated code as-is.
*/
String[] args() default {};
}
(UseViewer is the same, but value()'s value must extend Viewer.)
So, if you want to use a CreditCardEntryWidget, you'd probably define
a CreditCardEditor that either extends or wraps CreditCardEntryWidget
and implements Editor<String>. The CreditCardEditor might make use of
StringConverter<String> to enforce formatting rules:
public interface StringConverter<T> {
String toString(T value);
T fromString(String string) throws ConversionException;
}
Then, you'd do this:
public interface PersonForm extends Form<Person> {
// assumes Person.getCreditCard() returns an instance of something
// with a String getNumber() and a void setNumber(String)
@UseProperty("creditCard.number")
@UseEditor(CreditCardEditor.class)
Field<Person, String> getCreditCardNumber();
}
I'll see about posting the source to my library in the next half hour
or so, and I'll post it again when it's documented. I'd really like
some outside eyes on the code--I think it's useful but I'm sure it
could be improved.
Ian
The package ca.petersens.gwt.databinding.client contains most of the
interface to this library. Users of the code might also use the
annotation, converter, and ui subpackages. The generator is in
ca.petersens.gwt.databinding.rebind package. The "magic" mostly
happens in ca.petersens.gwt.databinding.client.impl. Something that
might be a stumbling block for users of the code is that your beans
have to implement
ca.petersens.gwt.databinding.client.SourcesPropertyChangeEvents for
the library to be able to listen to changes in beans.
When I release this "for real" I intend to use the same license as GWT
itself. It's not explicitly listed anywhere, but we may as well
consider the contents of the attached JAR to be licensed the same way.
Please share whatever thoughts you have--especially constructive
criticism. I'd like for this project to eventually be hosted
somewhere public and, if there's enough interest, for it to be part of
the incubator and/or GWT proper.
I just realized I should work up an example project that uses the
library. I'll get to that and post it shortly. To start with, you
can look at the documentation on ca.petersens.gwt.databinding.Form.
It's pretty bare, but it might give you some idea. Also have a look
at ca.petersens.gwt.databinding.client.ui.DataComposite and DataGrid.
Ian
I've started a pretty thorough example, but the office is closing and
I don't have a key so I have leave now. I'll probably post something
tonight, or maybe tomorrow.
Ian
Ian
I'm not sure what you mean. Are you looking to avoid updating the
bean until sometime after the editor has changed?
> - the converters are useful for general data mapping, but they also
> seem to be performing the role of validator. Is it possible to use the
> validation framework from the incubator or the one proposed here:
> http://code.google.com/p/google-web-toolkit/issues/detail?id=343#c30.
> Or, should the converters continue to perform the role of converting
> the data to match the binded data type? The converters wouldn't be a
> problem if the binding could be delayed and allow validation to run
> it's course.
I understand the converters as a way to map between a textual widget
and some non-String data type T. To me, a validator has as a first
assumption that the value it's validating is at least of the right
type. For example, validation on a birth date might require that the
birth date be before System.currentTimeMillis(), but the validator
would assume that it's validating a Date and not a String. In this
case, the converters are necessary as a first pass before the
validators.
I haven't looked at the validators, though, so I'll have a look when I
get to the office and think it over some more.
> - when executing Integer.parseInt() in the converters on non Integers,
> an exception should be thrown, but it seems to be getting caught
> somewhere. Where is that happening?
I'm guessing without looking at the source code, but I think you're
talking about HasTextEditor<T, W>.widgetChanged(). There's some code
that looks roughly like this (the code might be different, and there
aren't as many comments):
private void widgetChanged() {
try {
// calls converter.fromString(widget.getText());
this.value = doReadValue();
if (this.listeners != null && !this.listeners.isEmpty()) {
// fire an EditorChangeEvent to notify listeners...
}
}
catch (ConversionException e) {
// I think this is the exception you're expecting and I'm swallowing
}
// reformat and display the current value,
// which won't have changed if the user's
// input couldn't be parsed by the converter
doDisplayValue();
}
HasTextEditor<T, W> wraps a widget of type <W extends Widget & HasText
& SourcesChangeEvents> and it attaches a ChangeListener to that widget
that, in onChange(Widget sender), invokes the appropriate
widgetChanged() method. The widgetChanged() method takes care of
parsing the user's input into a value of type T. If the user's input
can't be parsed, the converter will throw a ConversionException, but
the HasTextEditor<T, W> swallows that exception and just redisplays
its previous value. This behaviour forces the widget to always be
displaying a value of type T formatted according to the subclass's
instructions.
> This framework looks very promising and well thought out. A less
> verbose binding mechanism would be nice, but I'm not entirely sure how
> it would be done. Thanks for the great work, I hope that this makes it
> into the incubator soon.
Thanks! And thanks for looking at it, too. Besides documentation
(and tests, I guess) another big thing that needs to be handled is
i18n. Right now, the best way to get nice labels for bound fields is
with the @Label annotation. That should probably go away and,
instead, the FormGenerator should spit out a Form implementation that
gets its labels from a properties file via a Constants subtype. I'm
not sure the best way to do that, though, because I haven't used GWT's
i18n facilities much.
Ian
I see. I hadn't thought of that use case. As it stands, no, you
can't do that. BoundFieldImpl<B, P> has a nested class Listener that
implements EditorChangeListener<P>. BoundFieldImpl's getEditor() adds
an instance of Listener as a change listener to the editor before
returning it. That listener takes care of updating the bean when the
editor changes and, as it stands, you can't not add the listener.
When I designed the library, I thought of bound widgets as views on
fields in a bean. If the bean changes, the widget is updated and if
the widget changes, the bean is updated. If you created a "detached"
editor that didn't automatically update the bean, what would you want
to happen if the bean were to change behind the scenes? Right now, if
the bean SourcesPropertyChangeEvents, the editors and viewers are
updated onPropertyChange. Would you want a detached editor to ignore
property change events from the associated bean?
> It'll also be interesting to see what the performance implications are
> of having the bean updated on any change. Does it work fine for forms
> of 100+ fields?
I haven't explicitly tested it with that many fields, but I'd expected
it to be okay--only the property bound to a given widget will be
updated when that widget changes. In the example I posted, the Person
class has firstName and lastName properties. When you edit a given
person, the firstName and lastName properties are bound to text boxes.
If you edit the first name, only the firstName property is updated
and likewise for the last name. Where there could be performance
considerations is if you have "lots" of viewers and/or calculated
fields all depending on the same property and then you edit that
property. I don't know what would happen then--the UI would probably
freeze until the updates were all complete. I'd be surprised if a
real application had a single field with 100+ dependent viewers,
though.
> Hmm, that's a good point. However, the way the current Converters work
> is that they remove the value that is entered by the user if it
> doesn't convert properly. As you mentioned, this probably has to do
> with the way exceptions are handled (putting back the previous value,
> which happened to be empty).
I don't mean to nitpick, but it's actually the editor that puts back
the previous value, not the converter. The converter just throws a
ConversionException if the String couldn't be converted. It's up to
the editor to decide what to do with the ConversionException. The
existing implementation of HasTextEditor<T, W> aims to be
"convertable" at all times, so a conversion exception in
widgetChanged() leads to redisplaying the previous value. You could
do something else, like leave the invalid input but mark the field
somehow. It's up to the application how it chooses to implement the
Editor<T> interface.
> I think that the validation that you have in mind is bean based
> validation, which is being discussed already (http://code.google.com/p/
> google-web-toolkit/issues/detail?id=343). This is different from the
> widget based validation which is currently in the incubator. Things
> are all over the place right now, and I think we need some direction
> from the GWT team.
I have a lunch appointment earlier than I expected, so I haven't had a
chance to look into validators or the link you just provided, but I'll
look into them this afternoon.
Ian
On Tue, Oct 7, 2008 at 1:51 PM, Arthur Kalmenson <arthu...@gmail.com> wrote:
>> I don't mean to nitpick, but it's actually the editor that puts back
>> the previous value, not the converter. The converter just throws a
>> ConversionException if the String couldn't be converted. It's up to
>> the editor to decide what to do with the ConversionException.
>
> Ah, sorry, I misunderstood how it was working. Thanks for clearing
> that up. This also deals with the original use case I proposed above
> (not updating the model right away). I only thought of that case
> because it kept trying to convert and reverting the field to it's
> previous value, which prevented validation from running its course.
> I'll just create my own editor and leave the field the way it was.
I read your comment on issue 343
(http://code.google.com/p/google-web-toolkit/issues/detail?id=343#c31).
I haven't finished reading the Bean Validation JSR yet, and I haven't
looked at Chris Ruffalo's code, but I have dipped my toe into using
Hibernate validation in my own server-side code. I *think* validation
could be tied into the data binding framework in a pretty
straightforward way by extending Editor<T> and Viewer<T> to be
validation-aware.
At the moment, Viewer<T> and Editor<T> just provide simple interfaces
to view (and edit) a value of type T. If there was some way to talk
about the validity of a given value, Viewer<T> (and, by extension,
Editor<T>) could be extended to provide feedback to the user when the
value it's displaying changes from invalid to valid or valid to
invalid.
I assume that Hibernate validation-style validation requires some kind
of "validation service" that is external to the beans being validated.
(As opposed to the beans themselves somehow performing validation and
reporting the results.) If that's the case, a BoundField could listen
to its editor for EditorChangeEvents and filter the new value through
validation before/after/around updating the related bean. If you
perform validation at that time, you have access to the editor that
changed, the bean that's (in)valid, the property that's (in)valid, and
the validation state. You could probably give very rich feedback to
the user about that particular property, and there are a number of
rational ways to handle an invalid value. Handling multi-property
validation is a little more complex but, assuming the validation
"service" can provide enough feedback, the bound field may be able to
co-ordinate with its containing BoundForm to manage the related
fields, or it could just punt and disallow the field change that
prompted the switch from valid to invalid, depending on what works in
context. As for validation "events" that happen "behind the scenes",
perhaps bound fields could somehow observe the validation service
using their knowledge of bean type and property name.
I think data binding and validation probably need to be aware of each
other (or, at least, data binding needs to be aware of validation),
but I think they're separate concerns. To me, data binding is just a
way of automating the display and update of a bean's properties via
some widgets. Validation, on the other hand, is a way of making sure
that a property is within some bounds, or some combination of
properties together follow some rules. Data binding impacts
validation because the user could transform a bean into or out of a
valid state, and validation impacts data binding because you usually
need to give the user feedback about the validity of the bean being
edited, but I think the relationship between data binding and
validation is probably best mediated through a thin interface that
keeps things loosely coupled.
What do you think? (Or anyone else, for that matter.)
> Ian, I think this data binding framework is really excellent. It's
> really well thought out and I think it'll be a major contribution to
> GWT. I hope it makes it into the incubator soon. Thanks for your hard
> work.
Thank you for the compliments and for taking the time to look into the
code and come up with questions and concerns--I'm sure you'll find
more as you dig deeper.
Ian
I can do that, but my week has suddenly filled up--I'm driving from
Toronto to Winnipeg tonight for a funeral and then I'll be back Sunday
night--so I'm not sure when things will get done. If I have internet
access between now and Sunday, I'll try to move forward during my
trip.
As for the rest of your post, I'll need to get back to it some other time.
Ian
Couldn't the API look more like this?
PersonForm form = GWT.create(PersonForm.class);
form.getFirstName().bind(existingWidget, personInstance);
form.getLastName().bind(anotherExistingWidget, personInstance);
or perhaps
form.bindInstance(personInstance).
getFirstName().bind(widget1).
getLastName().bind(widget2);
I realize there may be issues making this work with arbitrary
subclasses of Widget, but let's leave that aside for a moment and
assume the proper support can be added to the widgets. This would
also seem to work alot better with the proposed UI Templating system
being proposed.
-Ray
I can't answer you fully right now because I'm supposed to be leaving,
but I'll think about your suggestion and get back to you. As it is,
BoundFieldImpl constructs its editor lazily so perhaps a BoundField
could be given an editor rather than constructing one itself.
Also, regarding the problem of binding fields to arbitrary widgets, my
existing API works with Editor<T>s and Viewer<T>s. Both interfaces
define a Widget asWidget() that is expected to return this. In other
words, it's sort of assumed that implementations of Editor and Viewer
are also subclasses of Widget. Perhaps we don't need to worry about
arbitrary widgets because of that. If you want to look at my code,
take a peek at HasTextEditor<T, W> in
ca.petersens.gwt.databinding.client.ui. There could be more editors
like it to support certain subtypes of Widget.
Ian
On Wed, Oct 8, 2008 at 6:24 PM, Ray Cromwell <cromw...@gmail.com> wrote:
> Something struck me about the way you are approaching things, that
> is, letting the BoundField's return widgets. With the new HasData
> stuff being proposed, why not let the programmer create the widget,
> and bind the field to an already created widget? (if the widgets
> export an interface like HasData which permits wiring them up.) That
> seems to provide more flexibility, since people tend to design the
> look and layout of the widgets and wire up the logic separately.
>
> Couldn't the API look more like this?
>
> PersonForm form = GWT.create(PersonForm.class);
>
> form.getFirstName().bind(existingWidget, personInstance);
> form.getLastName().bind(anotherExistingWidget, personInstance);
>
> or perhaps
>
> form.bindInstance(personInstance).
> getFirstName().bind(widget1).
> getLastName().bind(widget2);
>
> I realize there may be issues making this work with arbitrary
> subclasses of Widget, but let's leave that aside for a moment and
> assume the proper support can be added to the widgets. This would
> also seem to work alot better with the proposed UI Templating system
> being proposed.
Sorry for the long delay--it's taking a while to come back to the real
world after a weekend that included about 45 hours in a car and a fair
amount of turkey.
Anyway, I've thought some more about your suggestion here (that
widgets be passed into the binding framework, rather than defining
them on the form), and I think I agree with you. Given that the same
value could be displayed/edited in more than one kind of widget, the
choice of _which_ widget seems like a presentation issue while the
business logic in the binding itself seems like a model issue. I
think that's enough argument for me that you're right. (As a bonus,
your suggestion also cleans up the smell of defining constructor
arguments in string form on the @UseEditor and @UseViewer
annotations.)
I do disagree with the particular APIs you suggested, though. To me,
a Form is to a class as a BoundForm is to an instance. I think it
should be possible to use the same form in multiple places at once,
and each "place" should be relatively independent, sharing only
definitions and not "instances". I'd therefore suggest something like
the following:
BeanForm form = GWT.create(BeanForm.class);
BoundForm<BeanType> boundForm = form.bindTo(beanInstance);
panel.add(boundForm.bind(form.getFieldOne(), new
TextBoxEditor(CurrencyConverter.INSTANCE));
panel.add(boundForm.bind(form.getFieldTwo(), new
LabelViewer(DefaultToString.INSTANCE));
panel.add(boundForm.bind(form.getFieldThree(), new CreditCardEditor());
The above code could be shortened if you assume it was in the context
of a DataComposite<BeanType> instead of in some random UI code:
public class BeanComposite extends DataComposite<BeanType> {
private static final BeanForm form = GWT.create(BeanForm.class);
// in retrospect, I really like this code--there's hardly any
// generic type cheese in the _use_ of the binding library
// anywhere except the definition of the form itself.
public BeanComposite() {
super(form);
FlowPanel panel = new FlowPanel();
panel.add(bind(form.getFieldOne(), new
TextBoxEditor(CurrencyConverter.INSTANCE)));
panel.add(bind(form.getFieldTwo(), new
LabelViewer(DefaultToString.INSTANCE)));
panel.add(bind(form.getFieldThree(), new CreditCardEditor()));
initWidget(panel);
}
}
// in random UI code
BeanComposite bc = new BeanComposite();
RootWidget.get().add(bc);
bc.setBean(new BeanType());
Regarding implementing widgets with "proper support" for a databinding
library like mine, I think that's a bad idea. At the moment, I still
like the declaration of intent implied by the Viewer and Editor
interfaces, so I'd expect BoundForm.bind() to be declared something
like this:
public interface BoundForm<B> {
/**
* Binds editor to field and returns editor. <code>P</code> is
field's value type.
*/
<P, W extends Widget & Editor<P>> W bind(Field<B, P> field, W editor);
/**
* Binds viewer to formula and returns viewer. <code>P</code> is
formula's value type.
*/
<P, W extends Widget & Viewer<P>> W bind(Formula<B, P> formula, W viewer);
}
Given HasData, it might be possible to write some really generic
implementations of Editor and Viewer that wrap an instance of HasData
to make it easier for developers to come up with an instance of Editor
to bind to, but I'm a little squirrelly about binding to arbitrary
widgets.
Thoughts?
Ian
PS I intend to look at the XForms spec as soon as I have some
time--I'm not ignoring your exhortations. :)
> Given HasData, it might be possible to write some really generic
> implementations of Editor and Viewer that wrap an instance of HasData
> to make it easier for developers to come up with an instance of Editor
> to bind to, but I'm a little squirrelly about binding to arbitrary
> widgets.
I think requiring the HasData interface isn't a bad thing, but this
might frustrate developers in the short term as standard GWT widgets
don't implement the HasData interface.
> Thoughts?
Overall it looks good. I like the new API idea.
P.S. Are you going to create a new Google Code project? It'd be easier
to track issues and contribute code. Thanks!
P.P.S. Nice to have a fellow Torontonian here :)
Regards,
--
Arthur Kalmenson
I don't expect to require HasData, I just expect to have some kind of
generic implementation for both Editor and Viewer that wrap a HasData
instance so that, given a HasData instance, you don't have to do any
work to integrate with the data binding library.
> Overall it looks good. I like the new API idea.
I think that settles it--I like it, too, and I guess your +1 makes me
not insane.
> P.S. Are you going to create a new Google Code project? It'd be easier
> to track issues and contribute code. Thanks!
Done. http://code.google.com/p/gwt-data-binding/ There's nothing
there yet, but I'll look into fixing that ASAP.
> P.P.S. Nice to have a fellow Torontonian here :)
Indeed, but I'll be a Seattlite in three weeks for a new job. Given
that, the next three weeks are going to be _very_ busy for me so I'm
not sure how much progress I'll be able to make in any given
direction.
Ian
Ah, thanks for clearing that up.
> Done. http://code.google.com/p/gwt-data-binding/ There's nothing
> there yet, but I'll look into fixing that ASAP.
Great, I've added a ticket already. The code would be helpful though
:P. We'd like to start sending in patches when we find some things to
change.
> Indeed, but I'll be a Seattlite in three weeks for a new job. Given
> that, the next three weeks are going to be _very_ busy for me so I'm
> not sure how much progress I'll be able to make in any given
> direction.
Oh, working for the enemy :P? Well good luck with your move, hope all goes well.
--
Arthur Kalmenson
OK, the code is there now, but what do you use to build your projects
usually? Do you use Maven or Ant? Personally, I prefer Maven....
--
Arthur Kalmenson
It's not really there yet. I'd like to mirror the changes I went
through in my private repository so other people can glean whatever
they can from the revision history so what's there now is the very
first version of my work.
Do you know what svnsync does? The svnsync help says that the
destination repository should be a "read-only mirror" of the source,
but I'd like to switch to the public repository for future
development. Can I svnsync and then start using it as a read-write
repo? Does svnsync copy all the history, or just the current version?
Does it track file moves like standard svn?
As for build tools, I'm using Ant myself. Right now, my private copy
of the data binding library is one piece of a big project so the build
script is external to the data binding piece. I intend to get my
revision history uploaded, then add a data binding-specific build
scrip to the public repo.
Ian
If your data bindings stuff was always in a specific folder of the
larger project, you should be able to svnsync that part of the project
into Google Code. Check out the "How do I import an existing
Subversion repository?" section here:
http://code.google.com/p/support/wiki/FAQ. It does track all svn
activity from that sub directory.
You might have to ask to have your svn repo reset to 0 so you can sync
it. Check out the Group here:
http://groups.google.com/group/google-code-hosting
--
Arthur Kalmenson
Thanks for the links. I'm most of the way through syncing it
manually, so I'll just go that route rather than asking someone to
reset the repo. Next time, though, I'll do it the easy way. :)
Ian