Nested forms: nested form is not visible

I have a Form. I tell it to use a custom field factory. The custom field factory returns a new Form() for one of the properties.

When my original Form is displayed on the screen, the nested Form is not visible. It is as though it simply does not exist.

I have checked through debugging that addField() is being called, and is being supplied with the nested form my field factory produces.

What is the reason for this? Are nested forms crippled and broken?

Thanks,
Laird

I sort of see what the problem is. At the time that my new Form is created, the property that it is designed to represent is null. Through a whole chain of method calls, this results in Form#setInternalValue() being called with a null Object. Since its prior value was also null (after all, I’m only just now creating it), it skips the Form#setFormDataSource() call. Consequently, no fields are ever rendered.

I wonder what the best pattern is here? I need to preserve the fact that the initial value of this form is null–it is perfectly viable for the property this form represents to be null–but I need to somehow have the form render its fields even when its value is null. Any thoughts?

Best,
Laird

La la la, talking to myself :slight_smile:

Nested forms are clearly not ready for primetime.

If your field factory returns a simple Form, then all sorts of 0-height problems result. I finagled a prototype-object-equals-null strategy to get my subform to actually render, and it did indeed render, but visually got tromped on by its superform’s footer. Yeeikes. I’ll wait for Vaadin 7.x to fix this.

(I’ve attached a screenshot showing the disaster on the latest released Firefox. The nested form occurs right before the “Release of Information” field; the point is that the subform is stomped on by subsequent fields in the superform.)

For those following along: do NOT try to use nested forms; they don’t work. Sure would have been neat if they did, but it’s complicated, and I’m not surprised they don’t.

Best,
Laird
11389.png

Lastly I should point out that in my field factory I do:

setSizeFull();

…on both the new subform itself as well as its contained Layout. The debug window continues to report that there are several 0-height problems. My intention, obviously, was to make sure that the subform itself took up as much space as it could from its container (the superform), and that the subform’s layout–a FormLayout, surely–took up as much space as IT could from ITS container (the subform). Neither of these strategies helped.

By this point I got fed up enough that I’m going to throw out the subform strategy and just flatten my data structures–easier all around. Hopefully the Vaadin crew knows immediately what’s going on here. For other users: avoid subforms; they simply don’t work (unless, perhaps, they’re at the bottom of their superform).

(I’ve attached a screenshot of the debug window showing the problems it thinks exist; note that emphasizing the various components involved actually doesn’t do anything, since, apparently, they’re all invisible. Prior to nested forms, I have no layout problems.)

Best,
Laird
11390.png

I’m also trying to use nested forms, and couldn’t find an example of how to do so. I did it as below, but I’m not sure this is the correct way to do it. Can someone please provide some guidance or an example?

Thanks!

Mark


  class BlueprintFormFactory implements FormFieldFactory{

    @Override
    public Field createField(Item item, Object propertyId, Component uiContext) {
      Field field = null;
      if(propertyId.equals(BlueprintItem.ASSET_WEIGHT)){
        field = new AssetWeightForm(item);
      }else{
        field = DefaultFieldFactory.get().createField(item, propertyId, uiContext);
      }
      
      return field;
    }
    
  }

public class AssetWeightForm extends Form{
  
  public AssetWeightForm(Item item){
    this.getLayout().addComponent(
        this.getFormFieldFactory().createField(item, BlueprintItem.ASSET_WEIGHT, this));
    this.setCaption("Asset Weight");
    this.setDescription("The weighting applies to the entire asset class");
    this.setSizeFull();
  }
  
}

I’m not sure how you got these problems, but I just implemented a fully functioning nested form. I’m using Vaadin 6.6.2 so I’m unaware if there has been a fix since then.

My parent form is inside of a window, it has a sub-form which is created by its FormFieldFactory. The biggest problem I had was that I forgot to call .setSizeUndefined() on the sub-form as it wasn’t pushing the width of the parent form (and therefore the window was too small).

Overall I’m loving the sub-form setup, it works beautifully with my nested beans. Not only having the FormFieldFactory.createField() calls cascading but also the form validation calls also cascading got me very excited. My dreams of never writing a ui component more than once are coming true.

Hi Scott,

I am too having problem in making the nested form work with nested beans.
Can you pl upload a sample so that others can also learn from it?

Thanks,
Pawan

Sounds real good Scott. Would love to see what you’ve done. Others may be able to benefit from it as well. Can you post your code (pseudo code works too)?

Paul

I was able to get the nested form to work. Take a look at the link below. It has a full working example.

http://code.google.com/p/customfield/source/browse/trunk/src/org/vaadin/addon/customfield/demo/NestedFormExample.java?r=24

Paul

This is a belated response, but hopefully it will be useful for people that search up this thread.

The method Paul outlines works but it is a bit mechanical, you’d have to do this every time you wanted to nest a form. Personally I hate re-writing code, every time I copy/paste and re-factor I check if I can make my code more generic.

The way I did this originally was to extend com.vaadin.ui.DefaultFieldFactory and override createField(…). This then inspects the item and based on its type it returns another form or calls super.createField(…). That might be a little hard to follow,this code is just from memory but you should get the idea. Assume that you have a parent form you’ve already set up, and that you’ve used MyFieldFactory as its field factory.


//bean backing the form
class SomeBean {

private Integer number;
private String name;
private Address address;

// getters/setters

}


//the address bean
class Address {

private Integer streetNumber;
private String street;
...

// getters/setters

}


//Field Factory
class MyFieldFactory extends DefaultFieldFactory {

public Field createField(Item item, Object propertyId, Component uiContext) {

if(item.getClass().equals(Address.class) {
AddressForm nestedForm = new AddressForm();
nestedForm.setDate(item);
return nestedForm;
}

}

}

And of course there is a class AddressForm extends Form which handles address beans, has a pretty layout, perhaps some styling, etc.

You can now call commit on the parent form and it will in turn call commit on all its fields. Since Form is actually a Field, the AddressForm will also get commit called on it. The same applies for validation checks. Basically, you don’t have to manually handle the nested form at all B)

It looks a bit messy, but you can wrap it up neatly and create your own common field factory that knows how to handle objects like Address, etc. Then you can use your common field factory everywhere instead of the default one and build up a little framework of custom fields/forms for specific beans. This is really nice for stuff like addresses because you dont have to muck around with a custom layout, etc everytime a bean has address information in it anymore.