1

I can't understand that part, neither trying the showcase examples.

I'm using an extension of AsyncDataProvider to bind my tree to RPC service. Here's my method:

public <T> NodeInfo<?> getNodeInfo(T value) {
        /*
        if (value instanceof Categoria) {
            dataProvider.setCurrentParent((Categoria)value);
        }
        */
        return new DefaultNodeInfo<Categoria>(dataProvider, new CategoriaCell());
    }

"currentParent" is my stuff: except for (null => root) values, I set the parent to pass via RPC to my service. Actually, in my widget code:

dataProvider = new CategorieTreeDataProvider() {            
            @Override
            protected void onRangeChanged(HasData<Categoria> display) {
                updateTree(getCurrentParent());
            }
        };

private void updateTree(Categoria categoria) {
        rpcService.getCategorie(categoria, new AsyncCallback<Categoria[]>() {
            @Override
            public void onSuccess(Categoria[] result) {
                dataProvider.updateRowCount(result.length, true);
                dataProvider.updateRowData(0, Arrays.asList(result));
            }
            @Override
            public void onFailure(Throwable caught) {
                Window.alert(caught.toString());
            }
        });
    }

My rpc-server code, however, is working as expected:

@Override
    public Categoria[] getCategorie(Categoria parent) {
        List<Categoria> categoryList = categorieDao.listByProperty("parent", parent);
        for (Categoria c : categoryList) {
            if (categorieDao.listByProperty("parent", c).size() == 0) {
                c.setLeaf(true);
            }
        }
        return categoryList.toArray(new Categoria[0]);
    }

**Then I add some data to my Categories: 'GrandFather', 'Father' and 'Son'.

Unfortunately, after loading my widget, I see:

  • The grandfather correctly, with his "+" how expected;

  • Then I click it and...

  • The grandfather disappear and I see 'Father' with his '+'

  • same for father -> son

I suspect the bug is in updateRowCount / updateRowData usage.**

Any ideas?

Nick Johnson
  • 100,655
  • 16
  • 128
  • 198
Fabio B.
  • 9,138
  • 25
  • 105
  • 177

2 Answers2

2

The getNodeInfo is called whenever you open a node so you have to create distinct DataProvider for each of the nodes's childs.

public <T> NodeInfo<?> getNodeInfo(T value) {
        if (value == null) {
            return new DefaultNodeInfo<Category>(dataProvider, new CategoriaCell());
        }
        else if (value instanceof Categoria) {
                 Category category  = (Category)value;
             return new DefaultNodeInfo<Grandfather>(new ListDataProvider<Grandfather>(category.getGrandFathers()),new GrandFatherCell());
        }
        else if (value instanceof Grandfather) {
             Grandfather grandfather = (Grandfather)value;
             return new DefaultNodeInfo<Father>(new ListDataProvider<Father>(granfather.getFathers()),new FatherCell());
        }
        else if (value instanceof Father) {
            //same as above but with fathers.
        }
    }

The category.getGrandFathers() function can for example do a RPC request to the server or just return the list if you retrieve everything in one RPC request.

UPDATE based on comment:

So in case you have only one class and want to achieve a dynamic CellTree (number of levels are not pre-determined) you could take following approach.

public <T> NodeInfo<?> getNodeInfo(T value) {
    if (value == null) {
        return new DefaultNodeInfo<Category>(dataProvider, new CategoriaCell());
    }
    else {
        Category category  = (Category)value;
        return new DefaultNodeInfo<Category>(new ListDataProvider<Category>(category.getSubCategories()),new CategoryCell());
    }
}

category.getSubCategories() is either an RPC call which retrieves the subcategories for the current category or if the Category class is a linked list type datastructure it could just return the list of subcategories.

Ümit
  • 17,379
  • 7
  • 55
  • 74
  • Good but... my tree is just a "infinite" tree! I don't know how many levels my user will create, it's up on him! So I have to write some 'universal' code, good for any number of levels. In addition, in my case, there are 'categories' at all levels: categories are child of other categories, they aren't different classes. :-\ – Fabio B. Aug 25 '11 at 08:02
  • Ok great, thank you very much! One last thing: what if I needed to "refresh" the tree from "the outside", maybe from my widget/composite class which holds the CellTree instance? I mean, for example, a "refresh" button, which fires in some way the dataProvider's update. Thanks a lot – Fabio B. Aug 25 '11 at 10:45
  • Yes you will probably save the instance of the root ListDataProvider somewhere . That's the one which contains the list of all root Categories. So in case your list updates you just have to update this dataProvider (by calling setRowData or setList). However there is a problem. When your CellTree is expanded and one of your sub categories changes you won't see the changes until you collapse and re-expand the CellTree again (because then getNodeInfo is called again) or you somehow manage to also update the DataProviders of the sub-levels. However this requires you to store them somewhere. – Ümit Aug 25 '11 at 10:49
0

Each data provider updates a given "list" (child nodes of a given parent node), so you have to use a distinct data provider instance for each parent node, or your calls will update some random list.

Thomas Broyer
  • 64,353
  • 7
  • 91
  • 164
  • These separate Dataproviders can be a little bit cumbersome. Especially if you dynamically update the underlying data. For example: If I display a hierarchical data structure (3 levels) in a CellTree, I have to create distinct Dataproviders for each CellTree level. If the CellTree is "expanded" and I update an object in level 2 or 3 (not in the root list) the CellTree View is not updated. I have to close the root node and reopen it again (because then getNodeInfo is called again). Is there a best practice for dealing with these use cases? Store DataProvider for each level and update them? – Ümit Aug 24 '11 at 11:22
  • @Thomas: maybe I didn't explained enough my problem. I am using one dataprovider, changing the parameter I pass to the rpc service, whenever a child node is requested, as you can see from my code, so... the bug is only in the gui: each time I request childs, they become roots of my tree, instead of appearing under the clicked 'parent'. How can I correctly update my gui?? – Fabio B. Aug 24 '11 at 21:05
  • @Fabio B.: the getNodeInfo is called whenever you open a node so you have to create distinct DataProvider for each of the nodes's childs. See answer below: – Ümit Aug 25 '11 at 07:08