GWT Editor and GXT Grid Not Sending Newly Created Proxy Entities, Only NULL Values

1.1k Views Asked by At

Does anybody have a solution to why I would be saving nulls to a OneToMany List on a server entity through a GXT Grid that contains a ListStoreEditor sub-editor?

I've followed the Sencha Example, GridBindingExample to a tee. http://www.sencha.com/examples/#ExamplePlace:gridbinding

public class MyEditor implements IsWidget, Editor<FooProxy> {
    interface Binder extends UiBinder<Widget, MyEditor> {}
    private static Binder uiBinder = GWT.create(Binder.class);

    public interface Driver extends SimpleBeanEditorDriver<MyProxy, MyEditor> {}    
    private Driver driver = GWT.create(Driver.class);

    private ListStore<BarProxy> store;
    ListStoreEditor<BarProxy> items;

    @Ignore
    @UiField(provided = true)
    Grid<BarProxy> grid;

    @Ignore
    @UiField
    ChildEditor childEditor;

    @Override
    public Widget asWidget() {
        MyProperties props = GWT.create(MyProperties.class);
        this.store = new ListStore<BarProxy>(props.key());

        List<ColumnConfig<BarProxy, ?>> columns = new ArrayList<ColumnConfig<BarProxy, ?>>();
        columns.add(new ColumnConfig<BarProxy, String>(props.itemName(), 300, "MyColumn"));

        this.grid = new Grid<BarProxy>(store,new ColumnModel<BarProxy>(columns));
        items = new ListStoreEditor<BarProxy>(store);

        Widget widget = uiBinder.createAndBindUi(this);
        driver.initialize(childEditor);

        childEditor.getCreateButton().addSelectHandler(new SelectHandler() {
            @Override
            public void onSelect(SelectEvent event) {
                RequestContext context = factoryProvider.get().barRequest();
                BarProxy entity = context.create(BarProxy.class);

                entity.setName("Eugene Qtest");
                entity.setAge(45);

                driver.edit(entity);
                store.add(driver.flush());  
            }       
        });

        return widget;  
    }
}

public class ChildEditor implements IsWidget, Editor<BarProxy> {
    interface Binder extends UiBinder<Widget, ChildEditor> {}
    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    TextButton createButton;

    @Override
    public Widget asWidget() {
        return uiBinder.createAndBindUi(this);
    }

    public TextButton getCreateButton() {
        return createButton;
    }
}

On an upper level presenter in my code, I am calling:

RequestContext req = editorPresenter.getDriver().flush();
req.fire();

This does save all data elements that the GWT Editor captures. In my database it does create the row for the grid in the above code, but all the values are null, so when the RequestContext fires, the persist brings back an empty row within the grid. So there is no foreign key to associate the entity in the OneToMany relationship back to its parent entity.

Also, I've looked at the JSON request and response to the server and it doesn't look like any of the values are being sent in the entity. It may be obfuscated, but it looks as though the other values are in plain text, so I don't think the proxy entity values are even being passed.

Any help would be great! Thanks

2

There are 2 best solutions below

0
On BEST ANSWER

This took me days to figure out, with the help of Colin in the above comments, Thanks!

The reason the grid was populating, but when you flushed the main editor on save, the values disappeared and a blank row was inserted into the grid, was because you have to implement the HasRequestContext interface on the editor to maintain the same RequestContext session. Below is my amended code.

public class MyEditor implements IsWidget, Editor<FooProxy>, HasRequestContext<FooProxy> {
    interface Binder extends UiBinder<Widget, MyEditor> {}
    private static Binder uiBinder = GWT.create(Binder.class);

    private RequestContext ctx;    

    private ListStore<BarProxy> store;
    ListStoreEditor<BarProxy> items;

    @Ignore
    @UiField(provided = true)
    Grid<BarProxy> grid;

    @Ignore
    @UiField
    ChildEditor childEditor;

    @Override
    public Widget asWidget() {
        MyProperties props = GWT.create(MyProperties.class);
        this.store = new ListStore<BarProxy>(props.key());

        List<ColumnConfig<BarProxy, ?>> columns = new ArrayList<ColumnConfig<BarProxy, ?>>();
        columns.add(new ColumnConfig<BarProxy, String>(props.itemName(), 300, "MyColumn"));

        this.grid = new Grid<BarProxy>(store,new ColumnModel<BarProxy>(columns));
        items = new ListStoreEditor<BarProxy>(store);

        Widget widget = uiBinder.createAndBindUi(this);
        driver.initialize(childEditor);

        childEditor.getCreateButton().addSelectHandler(new SelectHandler() {
            @Override
            public void onSelect(SelectEvent event) {
                RequestContext context = ctx.barRequest();
                BarProxy entity = context.create(BarProxy.class);

                entity.setName("Eugene Qtest");
                entity.setAge(45);

                ctx.edit(entity);
                store.add(entity);  
            }       
        });

        return widget;  
    }

    @Override
    public void setRequestContext(RequestContext ctx) {
        this.ctx = ctx;     
    }
}
3
On
            driver.edit(entity);
            store.add(driver.flush());  

These lines are saying "Draw the new object in the editor-- okay, take whatever value was put in there and add it to the store". I'm not sure this is what you intend.

Later, you reference an editorPresenter, but that doesn't seem to be in your code, and it isn't clear when you do that flush (or even the preliminary edit() call) and fire. You also make an Editor<BarProxy>, but there are no subeditors in that type to allow editing.

In the example you link to, there are two different drivers in the mix. The first takes care of the entire list, by passing it into the ListStore - this wasn't actually needed for the sake of an example, but is there to help explain how you might tie this into a bigger case, like the http://www.sencha.com/examples/#ExamplePlace:listpropertybinding example. The example should really be treated as two different editors, with two different drivers - doubly so when testing. First make sure one works, and returns the right values after driver.flush(), then the other.

As I started with, I think that your invocation of driver.flush() immediately after the edit call is almost certainly not what you want, (since the driver will have had no effect), so starting there would be good. Then, if that is what you want, test that when you receive the call on the server, you are getting the model object with all of its values.