-
FEATURED COMPONENTS
First time here? Check out the FAQ!
We have a grid with an extended ListModelMap and an extended RowRenderer. And we have a component that has buttons that when pressed will change the ListModelMap and thus we want it to update the grid.
We have reviewed http://www.zkoss.org/zkdemo/grid/dynamic_data and http://books.zkoss.org/wiki/ZK%20Developer%27s%20Reference/MVVM/Syntax/ViewModel/@NotifyChange
When the button is pushed we call the method to update the ListModelMap. We have logs to see the data change but our grid does not update. I expect that since the grids model has changed some sort of rerender event would be fired and the CustomerRowRenderer would run again.
Is the Map not bound to the grid simply by setting this map as the map for this grid? Do I need @NotifyChange and/or other annotations?
Here is some sudo code...(Everything we do is in java... no zul)
Calender calendar = Calender.getInstance(); Grid g = new Grid() SomeCustomHashMap hashMap = new SomeCustomerHashMap(calendar) CustomerListModelMap m = new ListModelMap(hashMap) CustomRowRender r = new CustomerRowRenderer(); g.setModel(m); g.setRowRenderer(r); SomeControlWithButtons ctrl = new SomeControlWithButtons(g); g.setParent(win); ctrl.setParent(win);
SomeCustomHashMap.java
public class SomeCustomHashMap extends HashMap { public SomeCustomHashMap(Calendar cal) { update(cal) } public void update(Calender cal) { ....goGetTheData....... for (.... theData...) { this.put(theDataKey, theDataValue); } } }
CustomListModelMap.java
public class CustomListModelMap extends ListModelMap { CustomListModelMap _m; public CustomListModelMap(SomeCustomHashMap m) { super(m, true); _m = m; .....doSomeOtherStuf..... } public void updateMap(Calendar cal) { _m.update(cal); } }
SomeControlWithButtons.java
public class SomeControlWIthButtons extends Box { public SomeControlWithButtons(Grid g) { Button b = new Button("Yesterday"); b.addEventListener("onClick", new EventListener<Event>(){ private Calendar cal = Calendar.getInstance(); @Override public void onEvent(Event event) throws Exception { ..... cal.setTheCalender........ ((SomeListModelMap) g.getModel()).updateMap(cal); } } ); } }
--Brad
I see..... thank you for the great explanation!
In my sample, I first thought, since I need to replace the whole hashMap, I might need to update CustomListModelMap.java as follows:
public class CustomListModelMap extends ListModelMap { CustomListModelMap _m; public CustomListModelMap(SomeCustomHashMap m) { super(m, true); _m = m; .....doSomeOtherStuf..... } public void updateMap(Calendar cal) { _m.update(cal); this.clear(); this.putAll(_m); } }
But I can't do that as the call to this.clear() will also clear _m. And not doing this.clear() the call to this.putAll(_m) will not remove any old key, value pairs that are not present in _m. I suppose I could clone _m, then clear, then putAll... yuck...
Unfortunately after all this I don't think I will use this method. Other details around the grid such as updating headers also need to be dealt with. Thus the complexity is getting a bit high. It looks like perhaps just rebuilding the entire grid may be a better solution. We will see....
Thank you all again....
--Brad
You cannot modify the original map that you passed to the ListModel. The whole point of using a ListModel is that you must make all changes using methods on the ListModel if you want them to have an effect on the grid.
Examples with live=true
Map original = new HashMap(); ListModelMap listModel = new ListModelMap(original, true); original.put(...) // Grid is NOT updated, because ListModel cannot know you have changed something listModel.put(...) // Grid is updated, because you made the changes through ListModel // The data structures are modified in both original and ListModel, because ListModel is just a view over the original map // However, if you modify the original directly, ZK cannot detect changes
Map original = new HashMap(); ListModelMap listModel = new ListModelMap(original, false); original.put(...) // ListModel will not be updated, and the grid will not be updated listModel.put(...) // Grid is updated, because you made the changes through ListModel. Original is unchanged // Original and ListModel are completely separate, because ListModel makes a copy of original // Modifying the original will not modify ListModel, and the grid will not see any updates
Thank you for the help.
grid.invalidate() did not help.
The javadocs say the following about invalidate
invalidate public void invalidate() Description copied from interface: Component Invalidates this component by setting the dirty flag such that it will be redraw the whole content of this component and its dependences later. And, the widget associated with this component and all its descendant at the client will be deleted and recreated, too. If the application is totally controlled by the server side (i.e., you don't write client codes), you rarely need to access this method. It can be called only in the request-processing and event-processing phases. However, it is NOT allowed in the rendering phase. Specified by: invalidate in interface Component
Concerning the paragraph above which starts, "It the application is totally controlled by the server....". It is not clear what the author considers "server side" or "client code". As you know all of the code resides on the server and only composed html and javascript are sent to the client. Perhaps the author meant java code vs zul markup language?
please make a try with
grid.invalidate();
instead of the second
setModel()
sometimes i have the same problems.
I messed with the annotation bindings a bit and that didn't work. I am not sure I was doing them right. But to me the bindings don't seem necessary in this scenario as I would think the setModel would perform the binding.
Of course another call to setModel would work but that defeats the purpose of binding all together.
The javadocs for ListModelMap say
Constructor Detail ListModelMap public ListModelMap(java.util.Map<K,V> map, boolean live) Constructor. Parameters: map - the map to represent live - whether to have a 'live' ListModel on top of the specified map. If false, the content of the specified map is copied. If true, this object is a 'facade' of the specified map, i.e., when you add or remove items from this ListModelMap, the inner "live" map would be changed accordingly. However, it is not a good idea to modify map if it is passed to this method with live is true, since Listbox is not smart enough to hanle it. Instead, modify it thru this object. Since: 2.4.0
So when called with live=true it should update.... although this "however" section here is a little worrisome... What does it mean "ListBox is not smart enough to handle it."? And what do they mean by modify it thru this object.... what do they mean by "thru" as one still has to update the hashMap and _m and m are the same animal.
I have also tried using a BindingListModelMap... although that seems like it used more for situations where the data is "paged"...
--Brad
Asked: 2012-10-24 02:39:27 +0800
Seen: 111 times
Last updated: Oct 24 '12