In GWT, How to use custom widget tag in an .ui.xml file with and without parameters for the tag in the same file - gwt

I am creating a custom widget, say "CustomWid" in UiBinder.
And in CustomWid.java file I am writing two constructors
one with zero args like
CustomWid(){....}
another with some args like
CustomWid(String a,String b){......}
So,Now I am using my custom widget in another .ui.xml file,in that .ui.xml file
it is working fine when we give
<my:CustomWid/> alone,
and also fine when we give like
<my:CustomWid a="srt1" b="str2"/> alone
But "MY PROBLEM" is whenever I am trying to give both the tags in the one .ui.xml as
<my:CustomWid/>
<my:CustomWid a="str1" b="str2"/>
Now it is throwing error when i am using both types of tags in a single .ui.xml
I mean How to use my custom widget tag like a prdefined tag?
I am using #uiConstructor, but it showing error
Please developers... I need answer as early as possible

UiBinder will only ever use a single constructor for a given widget: either its zero-arg constructor, or a #UiConstructor (I'm surprised that you say it works when using either one or the other call but not both: one should fail in every case, and one should succeed in every case; if you haven't annotated a constructor with #UiConstructor, then <my:CustomWid/> should always work and <my:CustomWid a="str1" b="str2"/> should always fail)
There are two solutions here:
use setters for the a and b attributes (void setA(String a) and void setB(String b))), and possibly check later (say, in onLoad or onAttach) that you have either none or both of A and B, but not one without the other (if that's your rule).
use #UiField(provided = true) when you need to use the other constructor (if you choose to have UiBinder use the zero-arg constructor –i.e. no #UiConstructor–, then that means you'll have to move the a="str1" b="str2" from the XML to the Java code: #UiField(provided = true) CustomWid myCustomWid = new CustomWid("str1", "str2")).
The first option has my preference.

It Will not show any errors...'
#UiConstructor
public Component(String displayText,String heading)
{
initWidget(uiBinder.createAndBindUi(this));
this.displayText.setText(displayText);
this.heading.setText(heading);
}`
now use another constructor with default parameters also it will work
public Component()
{
initWidget(uiBinder.createAndBindUi(this));
}
now if you add with xml parameters component and without parameters also works in the same page.

Related

GWT.create and wrap existing html element

Is it possible to create a TextBox using GWT.create, not the constructor, and wrap an existing HTML element?
I tried:
TextBox text=GWT.create(TextBox.class)
text.setElement(DOM.createInput()) (2)
The above fails on line (2) with "cannot set element twice ..."
I need this in order to use GwtMockito and test a component that needs to create a TextBox.
Thank you!
UIObject have a package protected replaceElement Method which will do what you like to do.
Building a wrapper in the right package like this:
package com.google.gwt.user.client.ui;
import com.google.gwt.dom.client.Element;
public class ElementReplace
{
public static void replaceElement(UIObject obj, Element elem)
{
obj.replaceElement(elem);
}
}
and it is possible to access the method.
It seems you'd have to resort to using some sort of factory:
public interface TextBoxFactory {
TextBox wrap(Element element);
}
This will get injected into your view and you'll use the factory to wrap the existing element in a TextBox. The default implementation will, of course, just use TextBox#wrap(Element), as suggested by Baz. For the purposes of your tests, you'll use an implementation that returns a Mockito mock.
Not the prettiest solution, but given the circumstances, I can't think of a "cleaner" one.

GWT #UiFactory and parameterized returned types

I have the following situation. There are two combos on my UI form, one shows the list of vegetables and another one shows a list of fruits.
In my supporting view class I'd like to declare such methods:
#UiFactory
SimpleComboBox<Vegetable> createVegetablesCombo() {
return vegetables;
}
#UiFactory
SimpleComboBox<Fruit> createFruitsCombo() {
return fruits;
}
But it seems that GWT does not recognize parameterized returned types... Every time I get an error:
ERROR: Duplicate factory in class VegetablesAndFruitsView for type SimpleComboBox.
Is it possible to handle this case? Is there a good example of multiple comboboxes on one UI form?
From the perspective of Java (not GWT, not UiBinder, but the Java language itself) at runtime there isn't a difference between SimpleComboBox<Vegetable> and SimpleComboBox<Fruit>. That said, this error is coming from UiBinder's code generation, which is looking for all #UiConstructor methods, and using them to build things.
So what does UiBinder have to work with? From the UiBinder XML, there is no generics. The only way UiBinder could get this right is if you happen to have included a #UiField entry in your class with the proper generics. This then would require #UiField annotations any time there might be ambiguity like this, something GWT doesn't presently do.
What are you trying to achieve in this? You are returning a field (either vegetables or fruits) - why isn't that field just tagged as #UiField(provided=true)? Then, whatever wiring you are doing to assign those fields can be used from UiBinder without the need for the #UiConstructor methods at all.
#UiField(provided=true)
SimpleComboBox<Fruit> fruits;
//...
public MyWidget() {
fruits = new SimpleComboBox<Fruit>(...);
binder.createAndBind(this);
}
...
<form:SimpleComboBox ui:field="fruits" />
If this is just an over-simplification, and you actually plan on creating new objects in those methods, then consider passing an argument in, something like String type, and returning a different SimpleComboBox<?> based on the value. From your UiBinder xml, you could create the right thing like this:
<field:SimpleComboBox type="fruit" />

GWT Reflection loading Form

I have a circumstance where I have to create a lot of forms for an application, the forms are all located in the same package. They are named like: A11111.java, A11112.java, etc.
When the user clicks in the NavigationPane, I wish to load the form into a TabItem and display the form. The issue is I need to dynamically generate the name of the form by appending the form name to the location, such as String formName = "com.foo.appName.client.forms" + e.getData("formCode"); something like that, where e is the event of the user click.
I have looked at several Reflection methods, but you cannot pass a derived string to them. How best to do this? Several posts mention using generators, but I get lost trying to sort their logic, and none have to do with displaying forms.
Note, I am not passing any variables to the forms, or calling any methods in the form java files, also the forms are created using uibinding.
Thanks in advance
if you're aiming at lazy-loading classes via the class-loader, like you would when using the command design pattern, note that it can't be done within a GWT application, as the frameworks JRE emulation only provides a subset of types and/or methods available in the JRE, so most of the reflection API - like forName() - will not be available.
rather than lazy-loading classes, think in terms of lazy-rendering widgets to the DOM. this can be achieved by instantiating all your form classes on module load, but only render upon tab-switching. place all your render-related functionality inside onRender() callbacks and you're good to go:
public class FormItem extends TabItem {
#Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
// render related functionality
}
}

Spring List Binding in Form

I'm trying to bind a list/arraylist/hashmap/etc of custom objects to my form in JSP using Spring. Right now, the controller creates a Map of the two lists (Boolean list and custom object list) in referenceData(), and provides it to the form which uses those values to populate the fields. The values are initialized from a MySQL database using Hibernate, and all that works fine. The list is a known length before the form is initialized, so that part is easier. Now what I'd like to do is correctly bind those objects in the form, so that when there are changes made, I can detect that in onSubmit() (or wherever is appropriate), and update the database accordingly. I can't seem to bind them correctly in the form so that I can see changes made. I tried just using a list of the form fields as the model, but even that wasn't working correctly. Do I just need to inject the list in a particular way? Any ideas or examples here? Any help would be greatly appreciated.
UPDATE: At Ralph's request here is the solution I used:
In my data object class, I lazy loaded a map using MapUtils.lazyMap(), with a String key and other custom object value. The other custom object is just a class that contains List<String> and getters/setters. In the corresponding .jsp file, I just nest several loops to loop through the keys first using loop.current.key and then loop2.current.value.paramsList to loop through the values for that key. This was not really what I asked for in my original post, as I was looking for a more general solution, and the lazy loading pointed me in the right direction.
In Spring 2 you need a special List in your Command object, that is able to grow if one add the x-th element event if the list has not this size yet.
One way to do that is to use LayzList decorator from commons-collections.
#Override
protected Object formBackingObject(final HttpServletRequest request)
throws Exception {
List<PosterSelectionRow> posterSelectionRowList = LazyList.decorate(
new ArrayList<PosterSelectionRow>(),
new PosterSelectionRowListFactory());
return new PosterSelectionCommand(posterSelectionRowList);
//PosterSelectionCommand contains a list of selected poster rows
}
private static class PosterSelectionRowListFactory
implements org.apache.commons.collections.Factory {
/** Invoked if the list need a new element */
public Object create() {
return = new PosterSelectionRow();
}
}
When I remember right, there is a way without that Factory stuff, but I am not sure.

Is it possible to get the ui:field value in java code in GWT?

This may sound very weird, but let's start with an example:
<my:MagicWidget ui:field="someFieldName" fieldName="someFieldName"/>
It's pretty much asured that we'll always want to have the same value in ui:field and in fieldName. Clearly there is some duplucation in this code, I'd like to avoid it and make the fieldName optional.
So, this is what I have in the widget's code:
#UiConstructor
public MagicWidget(String fieldName) {
this.fieldName = fieldName;
}
But I'd like, if possible to allow this constructor to be optional, and provide an default constructor that would "by magic" find out it's ui:field value:
#UiConstructor
public MagicWidget() {
this.fieldName = /*some magic to get ui:field's value*/;
}
I was wondering if there is a way to get the value of "ui:field" inside my MagickWidget? (The widget extends Composite). I fear this might not be possible, because most of the time it's not so useful, but if anyone has an idea - feel free to share!
PS: I'm using GWT 2.1.0.RC1.
As you may know, the ui:field is there so you can interact with a UI Object in Java code after you've declared it with UiBinder. So, for example, if you add a MagicWidget in a UiBinder template, you can write
#UiField MagicWidget someWidget
in order to be able to interact with it programatically. Having your magic widget aware of the name of the reference that is pointing to it might not be all that helpful (or possible), as you can pass the reference to that specific MagicWidget back and forth between different parts of your application. A single MagicWidget could easily have several references with different names pointing at is simultaneously. That's why it's difficult to pick it out "by magic" at runtime. I realize this isn't much of an issue if you only want this value when the object is constructed, but keep in mind that you're not required to include a ui:field when you add a widget using UiBinder.
Why is it important that the Widget know its field name? Knowing that might make it easier to provide suggestions about other ways to accomplish what you are looking to do.