Cancel CellList selection

1,299 views
Skip to first unread message

Yann

unread,
Nov 9, 2011, 5:42:19 AM11/9/11
to Google Web Toolkit
Hello,

Is there a way to cancel a user selection of a row in a "CellList" ?
I can't find something like a "BeforeSelectionHandler" on a
"TabLayoutPanel".
I would like to be able to prompt a message indicating that the
current edited object of the CellList has not been saved if the user
clicks on another cell.
Any idea ?

Thanks.
Yann.

Thomas Broyer

unread,
Nov 9, 2011, 10:13:12 AM11/9/11
to google-we...@googlegroups.com
Try with a custom CellPreviewEvent.Handler; possibly delegating to a DefaultSelectionEventManager for the default behavior.

Yann

unread,
Nov 10, 2011, 4:29:29 AM11/10/11
to Google Web Toolkit
Hello Thomas,

Thanks a lot for your response but what do you mean by "Try with a
custom CellPreviewEvent.Handler".

I tried :

myCellList.addCellPreviewHandler(new
CellPreviewEvent.Handler<MyObject>(){
@Override
public void onCellPreview(CellPreviewEvent<MyObject> in_event){
System.out.println(in_event);
}
});

But "onCellPreview" is never called !

Yann

unread,
Nov 10, 2011, 4:48:18 AM11/10/11
to Google Web Toolkit
Apologies Thomas, "onCellPreview" is actually called !
I didn't find yet which native event I should cancel, but I'm working
on it...

Thomas Broyer

unread,
Nov 10, 2011, 6:12:57 AM11/10/11
to google-we...@googlegroups.com
It's not about cancelling the event; it's about *not* routing it to a DefaultSelectionEventManager (which changes selection depending on the event). It also means you shouldn't addCellPreviewHandler, but instead use the two-argument overload of setSelectionModel.

It's as easy as:
myCellList.setSelectionModel(mySelectionModel, CellPreviewEvent.Handler<MyObject>() {
   private final CellPreviewEvent.Handler<MyObject> defaultSelectionManager = DefaultSelectionEventManager.createDefaultManager();
   @Override
   public void onCellPreview(CellPreviewEvent<MyObject> event) {
      if (hasUnsavedChanged() && !Window.prompt("There are unsaved changes, are you sure you want to continue?") {
         return;
      }
      return defaultSelectionManager.onCellPreview(event);
   }
});

Beware though, if you have a cell that "handlesSelection()", you'll have to handle the case there (so that it doesn't change selection if there are unsaved changes).

Oh, and it just occurred to me that you could also simply code that within your SelectionModel too:
class PromptingSelectionModel<T> extends SingleSelectionModel<T> {
   @Override
   public void setSelected(T object, boolean selected) {
      if (hasUnsavedChanged() && !Window.prompt("There are unsaved changes, are you sure you want to continue?") {
         return;
      }
      super.setSelected(object, selected);
   }
}

Yann

unread,
Nov 10, 2011, 11:45:57 AM11/10/11
to Google Web Toolkit
Thomas,

Overriding SingleSelectionModel.setSelected() works like a charm.
It's so obvious I really should have figured it by myself...
Thanks a lot !

BM

unread,
Jan 29, 2013, 12:43:11 PM1/29/13
to google-we...@googlegroups.com
I was looking something similar and your example is perfect. I am going with approach of having my custom SingleSelectionHandler i.e PromptingSelectionModel . My view is more like GWT Showcase CellList-DetailForm example. If I click on my cell, my code populates the form elements. My Form is a separate GWT custom widget FormAWidget with its own presenter FormAPresenter. 

So with that being said, I probably will be storing a variable "hasUnsavedChanged" in ClientFactory which gets updated whenever my form data is changed. How do I get that variable inside my PromptingSelectionModel class so that I can check that variable in my overridden setSelected method? Since I use GWT MVP structure my ViewA holds declaration of CellList and PromptingSelectionModel. The ActivityA has reference to ClientFactory, the only way I can think of is passing the ClientFactory to my ViewA class with setClientFactory(ClientFactory cf) and pass that ClientFactory object to PromptingSelectionModel constructor. I don't like the idea of my views now having reference of ClientFactory. 

Please advise if you can see any better way of doing this. I always follow GWT Activities and Places paradigm where my Views hold GWT widgets and getter and setter methods to talk to its Activity class based on what Ray Ryan suggested with MVP Activities and Places approach.

Thomas Broyer

unread,
Jan 31, 2013, 6:22:13 AM1/31/13
to google-we...@googlegroups.com


On Tuesday, January 29, 2013 6:43:11 PM UTC+1, BM wrote:
I was looking something similar and your example is perfect. I am going with approach of having my custom SingleSelectionHandler i.e PromptingSelectionModel . My view is more like GWT Showcase CellList-DetailForm example. If I click on my cell, my code populates the form elements. My Form is a separate GWT custom widget FormAWidget with its own presenter FormAPresenter. 

So with that being said, I probably will be storing a variable "hasUnsavedChanged" in ClientFactory which gets updated whenever my form data is changed. How do I get that variable inside my PromptingSelectionModel class so that I can check that variable in my overridden setSelected method? Since I use GWT MVP structure my ViewA holds declaration of CellList and PromptingSelectionModel. The ActivityA has reference to ClientFactory, the only way I can think of is passing the ClientFactory to my ViewA class with setClientFactory(ClientFactory cf) and pass that ClientFactory object to PromptingSelectionModel constructor. I don't like the idea of my views now having reference of ClientFactory.

"ClientFactory" (if you copied it form the Dev Guide) is supposed to be about "manual dependency injection". You shouldn't pass it around (if you were using a JSR330 DI framework or similar, such as GIN, you wouldn't even pass it to the activities, you'd instead inject a Provider<HelloView>). If you happen to need it in the view, then give it to the view when it's constructed (the view is constructed by the ClientFactory, right?)

That said, I believe the selection model should live in the presenter: it's part of the "presentation logic".

Please advise if you can see any better way of doing this.


Avoid global shared state. Don't put "hasUnsavedChanges" in your ClientFactory. That information belongs to your form (and in this case, its presenter). Then inject objects into each other as needed so they have access to the information.

 

BM

unread,
Jan 31, 2013, 12:10:07 PM1/31/13
to google-we...@googlegroups.com
I tried to use the similar code for PromptingSelectionModel class. It works but the only different is that for unsaved form data, although it prevents the selection of next cell it leaves a mild yellow selection on. So I see blue selection of first cell and mild yellow selection on second cell. Do I need to clear that selection on second cell if unsaved form data and window.confirm yields true?


On Thursday, November 10, 2011 5:12:57 AM UTC-6, Thomas Broyer wrote:

BM

unread,
Jan 31, 2013, 12:28:02 PM1/31/13
to google-we...@googlegroups.com
Thanks Thomas. Unfortunately we are not using any DI framework. So we are going by traditional GWT Activities and Places framework with ClientFactory being passed to my Activity from AppActivityMapper. 

Interesting. I never thought declaration of SingleSelectionModel model should be in Activity although I understand we can mock SingleSelectionModel for testing. So I guess the selectionModel.addSelectionChangeHandler code will also go in Activity/Presenter class right? 

The reason I put the flag it in ClientFactory is I wanted to make it a global variable so that it could be reusable from different Views that has List-Details screens. When user arrives on the form, reset the flag in ClientFactory to false. When user saves the form successfully, reset that flag to false as there are not unsaved changes. When user update the form set the value to true onValueChange event of its GWT widgets(textbox, SelectBox, etc). That way not only I can show that pop-up alert message if the user clicks on different cell in the Cell List within the same view but also if the user tries to navigate away to a different tab in my app, I can check that variable globally thru some PlaceChangeEvent. I thought putting a global variable would be easier than having every view to handle logic of updating the local flag within its presenter. 

BM

unread,
Jan 31, 2013, 1:53:34 PM1/31/13
to google-we...@googlegroups.com
I also realized that the overriden setSelected method is called two times in PromptingSelectionModel. So if I selected Cell 7 and Cell 7 is currently selected and if I click on Cell 10, the the cell selection is about to changed the first call to overriden setSelected method passes Cell 7 object and selected flag as false and second call passed Cell 10 object and selected flag now is true. So having that unsavedFlag check shows me two Confirm dialog boxes assuming the form data on Cell 7 has changed. Hitting cancel twice keeps the Cell 7 selected but it also shows a mild yellow selection color on Cell 10. 

So it seems when a selection is changed GWT removes the first selection (selected off) and selects the next selection (selected true). So when I override the setSelected method, I somehow need to stop the second call if my form is not saved. Not sure how do I do that.
Reply all
Reply to author
Forward
0 new messages