Selecting list items from history actions using Activities and Places

111 views
Skip to first unread message

Shaun Tarves

unread,
Feb 29, 2012, 8:30:21 AM2/29/12
to google-we...@googlegroups.com
Hi all -

First off, thanks for all the great info on this board. I've gotten so much out of it. However, I'm having a problem I haven't seen addressed before. Here's my scenario:

1) I have 2 places, 2 separate activity managers/mappers (one for a "menu" display area and one for "content" display area).

2) In the menu area is a basic CellList, with an attached selection handler that fires an event registered on the app's event bus to go to a new place. It also naturally "selects" the item in the menu.

Selection of items/going to new places works naturally when the user is clicking around. 

My problem:

When any history action is involved (via a direct URL or using back/forward in the browser), how to I handle selecting the appropriate item in the menu?

The obvious choice is a place change handler in the menu, which, in turn, uses the menu's selection handler to select the appropriate item. BUT, since the selection handler fires an event to go to a new place upon selection, it introduces circular logic. (onPlaceChange does setSelected, then onSelection fires an event to change places)

It's disconcerting that none of the sample apps (expenses, mobilewebapp) do any kind of item selection when you navigate DIRECTLY to a place via URL, but this seems like a really basic feature of a web application.

Thoughts?

Chris Price

unread,
Feb 29, 2012, 1:22:58 PM2/29/12
to google-we...@googlegroups.com

I thought singleselectionmodel swallowed setting the selected value to itself?

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/kLEBTO6gJuIJ.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Shaun Tarves

unread,
Feb 29, 2012, 3:51:51 PM2/29/12
to google-we...@googlegroups.com
It does, but this is a differrent issue. The selectionmodel needs to be notified of selection somehow if the user isn't selecting with mouse or keyboard. 

My problem is when the user navigates to a state in the app where an item should appear to be selected  - directly via a URL (as supported by activities/places) or using back/forward buttons - rather than by clicking.

For example, I click an Item in the CellList, the onSelection change handler fires an event to go to a new place. The Item appears selected...all is good. However, when the user clicks the back button, for example, I now need to select a DIFFERENT item in that CellList to represent the last place they were on. The history manager fires some placeChangeEvent that I can listen for. So I attach a handler to that PlaceChangeEvent that tells the list to select and item.

The problem is that the selection handler, upon being told to select the item representing where I actually am, will AGAIN fire the event to go to a new place (as it should). Now, I've got a bad loop.

I hope that makes the problem clearer. I can't wrap my head around how to make this work.

- Shaun

Thomas Broyer

unread,
Mar 1, 2012, 4:31:14 AM3/1/12
to google-we...@googlegroups.com

Chris Price

unread,
Mar 1, 2012, 4:50:16 AM3/1/12
to google-we...@googlegroups.com
I've knocked up a quick example of what I was meaning, I think it
works for all the cases you described. I'd be interested in how your
app is different -

https://github.com/chrisprice/menubodyexample/blob/master/src/com/scottlogic/cprice/menubodyexample/client/menu/Menu.java

(n.b. the instanceof and string equality code is a dirty hack!)

> --
> You received this message because you are subscribed to the Google Groups
> "Google Web Toolkit" group.
> To view this discussion on the web visit

> https://groups.google.com/d/msg/google-web-toolkit/-/oGLD5HqYR0cJ.

Jens

unread,
Mar 1, 2012, 5:14:23 AM3/1/12
to google-we...@googlegroups.com
You may also want to read: https://groups.google.com/d/topic/google-web-toolkit/dTwvMbxlFgI/discussion

Its not directly related to your problem but as you are firing place changes by listening on the selection model it could happen that your UI may gets inconsistent. This can happen if you use Activity.mayStop() to provide warning messages and the user chooses to cancel a place change. Without considering this case your list will have the new item selected (because you clicked on it and CellList updates the selection model) while your details view still shows the old item (because the user cancels the place change).

-- J.

Shaun Tarves

unread,
Mar 1, 2012, 9:23:01 AM3/1/12
to google-we...@googlegroups.com
@Thomas - In the example you pointed me to, what prevents this from essentially creating an infinite loop? OnSelectionChange fires a new history event. The history handler responds, gets info and changes the selection, which would in turn fire a new history event. No?

@Chris - I think it's the same situation...your selection handler fires a new place, which selects and item, which would in turn fire a new place request. Right?

Am I missing something here?

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

Chris Price

unread,
Mar 1, 2012, 9:31:02 AM3/1/12
to google-we...@googlegroups.com
In my example this is caught by the following in
SingleSelectionManager, which traps setting the selected value to be
itself -
http://code.google.com/codesearch#T04cSGC7sWI/trunk/user/src/com/google/gwt/view/client/SingleSelectionModel.java&q=abstractselectionmodel%20package:http://google-web-toolkit%5C.googlecode%5C.com&l=106

However, Jens raises a very good point about the potential downside of
this approach.

Chris

Shaun Tarves

unread,
Mar 1, 2012, 9:38:50 AM3/1/12
to google-we...@googlegroups.com
It still seems like an extra "event" at the very least. User selects, which fires selection change, which fires new place, which then "reselects" the item (the loop ends here since there no selection change would be fired given that the item is already selected).

BUT, in the case of history movement (back/forward), new place is requested, place change is fired, which selects item, which fires selectionchange, which then again goes to new place.

How would you not get an extra item on the history stack with this approach?

Chris Price

unread,
Mar 1, 2012, 9:44:30 AM3/1/12
to google-we...@googlegroups.com

Thomas Broyer

unread,
Mar 1, 2012, 10:28:39 AM3/1/12
to google-we...@googlegroups.com

On Thursday, March 1, 2012 3:23:01 PM UTC+1, Shaun Tarves wrote:
@Thomas - In the example you pointed me to, what prevents this from essentially creating an infinite loop? OnSelectionChange fires a new history event. The history handler responds, gets info and changes the selection, which would in turn fire a new history event. No?


If the value to be selected is the same as the already-selected one, then no SelectionChangeEvent is fired.
If the place to go to is the same as the current place, then this is a no-op too.

So there's no infinite loop. 

Shaun Tarves

unread,
Mar 1, 2012, 10:31:56 AM3/1/12
to google-we...@googlegroups.com
Hi Thomas/Chris -

Thanks for the responses. I was missing the part about the build-in check for Place equality. Any idea how the equality check is implemented?

For example, if my Place has 2 fields - an integer and a string, is it implicitly true that 2 places are equal if those values are the same in both, or do I need to explicitly define an equals() method?


--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

Chris Price

unread,
Mar 1, 2012, 10:34:53 AM3/1/12
to google-we...@googlegroups.com
See the highlighted line in the link I posted, or here's the code -

public void goTo(Place newPlace) {
log().fine("goTo: " + newPlace);

if (getWhere().equals(newPlace)) {
log().fine("Asked to return to the same place: " + newPlace);
return;
}

String warning = maybeGoTo(newPlace);
if (warning == null || delegate.confirm(warning)) {
where = newPlace;
eventBus.fireEvent(new PlaceChangeEvent(newPlace));

Shaun Tarves

unread,
Mar 1, 2012, 10:40:51 AM3/1/12
to google-we...@googlegroups.com
I saw that...I meant in my specific Place class. Is it best practice to explicitly implement my own equals() method even if the standard Object.equals would suffice?

Do you see any advantage?

Furthermore, how does this relate to the cachedActivityMapper? I read in a post on this board somewhere that's it's better to implement the cached/filtered mappers rather than override equals(). Thoughts on this?

Jens

unread,
Mar 1, 2012, 10:54:04 AM3/1/12
to google-we...@googlegroups.com
Provide a correct equals()/hashcode() implementation in your places as mentioned in JavaDoc for Place.java.

If you don't do so, CachingActivityMapper wont cache anything because it also does an oldPlace.equals(newPlace) to see if it can return the cached activity.

-- J.
>> To post to this group, send email to google-web-toolkit@googlegroups.com.

>> To unsubscribe from this group, send email to

>> For more options, visit this group at
>> http://groups.google.com/group/google-web-toolkit?hl=en.
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Google Web Toolkit" group.
> To post to this group, send email to google-web-toolkit@googlegroups.com.

> To unsubscribe from this group, send email to

> For more options, visit this group at
> http://groups.google.com/group/google-web-toolkit?hl=en.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsub...@googlegroups.com.

Thomas Broyer

unread,
Mar 1, 2012, 12:03:13 PM3/1/12
to google-we...@googlegroups.com


On Thursday, March 1, 2012 4:54:04 PM UTC+1, Jens wrote:
Provide a correct equals()/hashcode() implementation in your places as mentioned in JavaDoc for Place.java.

If you don't do so, CachingActivityMapper wont cache anything because it also does an oldPlace.equals(newPlace) to see if it can return the cached activity.

...if you don't do this, you risk an infinite loop... (well, the loop should be broken by the SelectionModel, which shouldn't fire an event when you don't actually change the selection)

Shaun Tarves

unread,
Mar 2, 2012, 3:56:44 PM3/2/12
to google-we...@googlegroups.com
This worked out fine. However, the obvious issue is that it's pretty hard to have anything done in your app BEFORE that initial PlaceChangeEvent (say, if you directly go to a specific place via the URL) gets fired.

My solution was to write the same logic in both a placeChangeHandler and on initialization of the menu to select an item.

Thanks for the help.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/9n07mtAs3foJ.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.

Chris Price

unread,
Mar 3, 2012, 6:25:33 AM3/3/12
to google-we...@googlegroups.com

Shaun Tarves

unread,
Mar 3, 2012, 8:39:45 AM3/3/12
to google-we...@googlegroups.com
What I meant is that in your app structure, you'll typically have a call to initBrowserHistory pretty early on. That will fire the initial placeChangeEvent. When that happens, the activity containing the menu hasn't event been started yet (or likely instantiated even), so the placeChange handler isn't available to listen for that event.

That is of course assuming you follow the typical activities/places set up with multiple activity mappers, etc

- Shaun

Chris Price

unread,
Mar 3, 2012, 8:49:23 AM3/3/12
to google-we...@googlegroups.com
I see what you're getting at.

Not that it helps, but that link was meant to be -

https://github.com/chrisprice/menubodyexample/blob/master/src/com/scottlogic/cprice/menubodyexample/client/Menubodyexample.java#L48

i.e. historyHandler.handleCurrentHistory();

Shaun Tarves

unread,
Mar 3, 2012, 8:52:54 AM3/3/12
to google-we...@googlegroups.com
That's pretty much the same way my app is set up, so you can see the
problem. Like I said, I solved it by essentially repeating the same
code as in the placeChangeHandler in the activity start() method, but
it seems little hokey.

Any ideas how to make this a little cleaner?

- Shaun

Reply all
Reply to author
Forward
0 new messages