Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 395053

Summary: [List] Scrolling with topIndex does not work if items are loaded at the same time
Product: [RT] RAP Reporter: Claudio Guglielmo <claudio.guglielmo>
Component: RWTAssignee: Project Inbox <rap-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P2 CC: ivan, tbuschto
Version: 1.5   
Target Milestone: 2.1 RC1   
Hardware: PC   
OS: Windows 7   
Whiteboard:
Attachments:
Description Flags
Example, images and workaround (patch) none

Description Claudio Guglielmo CLA 2012-11-26 05:25:02 EST
Created attachment 223942 [details]
Example, images and workaround (patch)

I'd like to scroll to the bottom of the list. To do this, I create a list and set topIndex to itemCount -1. But: It doesn't scroll.
If I set topIndex on a list which already contains items, it works fine. 

A little debugging showed, that the scroll position is set before the items are actually rendered. 

See the attached snippet for example code. The attachment also contains a workaround as patch which makes it better but still not perfect. See the images for details.

If I use a table, it works. I assume because of the following code: 

if( this._inServerResponse() ) {
        this._scheduleUpdate( "topItem" );
      } else {
..
}

Probably something like that needs to be done for the list too.
Comment 1 Tim Buschtoens CLA 2012-12-07 10:24:07 EST
Actually, the List already accounts for this scenario with this code:

    _onAppear : function( evt ) {
      // [ad] Fix for Bug 277678
      // when #showSelection() is called for invisible widget
      this._applyTopIndex( this._topIndex );
    },

Not sure yet why it still doesn't work correctly. 

Also, please attach patches and snippets uncompressed. That makes it much easier to take a look at them quickly. Thanks.
Comment 2 Ivan Furnadjiev CLA 2012-12-07 10:38:56 EST
(In reply to comment #1)
> Actually, the List already accounts for this scenario with this code:
> 
>     _onAppear : function( evt ) {
>       // [ad] Fix for Bug 277678
>       // when #showSelection() is called for invisible widget
>       this._applyTopIndex( this._topIndex );
>     },
> 
> Not sure yet why it still doesn't work correctly. 
> 
> Also, please attach patches and snippets uncompressed. That makes it much
> easier to take a look at them quickly. Thanks.

I think that the problem exists when the List is already created on the client and you you change items and topIndex in a single request. Items are rendered before topIndex in ListAdapeter.js, but maybe a flush of new created DOM elements is needed to correctly respect the topIndex change.
Comment 3 Tim Buschtoens CLA 2013-01-04 10:33:30 EST
Fixed with commit f1ca48b62412473a984566c0f8f25b4c39ecab73.

The problem was that the scroll position has to be applied to the html-element AFTER the items have already been rendered, which happens in the display-flush.

This had to be fixed on several levels:
1. The position value has to be applied to the scrollbar, not the clientArea directly, but after the scrollbars maximum has been updated.
2. Doing so triggers _syncClientArea in Scrollable.js, which now detects that the position could not be set yet, an schedules it to be applied AFTER the next flush.

I'm hesitant to apply this to 1.5, as it's a relatively big change. On the other hand it's mostly additional code that can't really do any harm.
Comment 4 Ralf Sternberg CLA 2013-01-22 06:11:25 EST
In a discussion with Tim, we agreed not to include this fix in the 1.5.2 service release. It overrides methods of Scrollable and involves a slight risk of breaking something else. The bug only affects code that uses a certain pattern - adding an item and immediately setting the top index of a List. As a workaround, the top index can be set in a timerExec in 1.5.
Comment 5 Claudio Guglielmo CLA 2013-02-12 12:50:24 EST
Thanks for solving the bug, Tim! I did a little test and it works way better, but still not perfect. Run the already attached example and scroll a little bit upwards. Then press on the button "add more elements and scroll to bottom". The elements are added but it only scrolls to the former last element, which is Item 99 instead of Item 119.
Comment 6 Tim Buschtoens CLA 2013-02-13 10:43:32 EST
(In reply to comment #5)

Indeed.

It looks like at some point Scrollable.js#_internalChangeFlag is set to the wrong value (false), and the desired scroll position is lost for that reason.

The whole native-html scrolling thing is a nightmare. Using "top" (or css transform where possible) instead of "scrolltop" would be so much simpler. The only reason we don't use it is because some input methods for scrolling (touch and scroll wheel) would have to be implemented explicitly, and might not behave as the user is used to. Perhaps it's worth the effort anyway.
Comment 7 Claudio Guglielmo CLA 2013-02-13 12:47:34 EST
I must admit I am not very familiar with the Scrollable.js so I can't help you with that. But I just did the same test with rap 1.5 and my little workaround in _applyTopIndex and it seems to work. Maybe this info helps... 

var func = function() {
  if(this._clientArea != null) {
    this._clientArea.setScrollTop( newIndex * itemHeight );
  }
};
qx.client.Timer.once( func, this, 60 );
Comment 8 Tim Buschtoens CLA 2013-05-14 10:30:35 EDT
It looks like the issue is in the ScrollBar. The scroll position may be changed during an internal layouting process: 

console.trace() rap-client.js:58967
rwt.qx.Class.define.members._syncClientArea rap-client.js:58967
rwt.qx.Class.define.members._onVertScrollBarChangeValue rap-client.js:58929
rwt.qx.Class.define.members._dispatchEvent rap-client.js:6260
rwt.qx.Class.define.members.dispatchEvent rap-client.js:6190
rwt.qx.Class.define.members.createDispatchEvent rap-client.js:6124
rwt.qx.Class.define.members._dispatchValueChanged rap-client.js:35740
rwt.qx.Class.define.members._updateStepsize rap-client.js:35747
rwt.qx.Class.define.members._updateThumbSize rap-client.js:35391
rwt.qx.Class.define.members.base rap-client.js:5180
rwt.qx.Class.define.members._updateThumbSize rap-client.js:35646
rwt.qx.Class.define.members._setThumb rap-client.js:35134
rwt.qx.Class.define.members._layoutPost rap-client.js:35672
rwt.qx.Class.define.members._layoutChild rap-client.js:16725
rwt.qx.Class.define.members.flushChildrenQueue rap-client.js:19462
rwt.qx.Class.define.members._flushChildrenQueue rap-client.js:16663
rwt.qx.Class.define.statics.flushGlobalLayoutQueue rap-client.js:9246
rwt.qx.Class.define.statics.flushGlobalQueues rap-client.js:9087
rwt.qx.Class.define.members._handleSuccess rap-client.js:69685
_success rap-client.js:36179
rwt.remote.Request._onReadyStateChange rap-client.js:36230
wrap
Comment 9 Tim Buschtoens CLA 2013-05-15 11:34:25 EDT
Fixed (again) with commit 8be427df5f996449f9ccb021229d53828e3c27cd.

There were multiple issues, but the main one was that some browser fire the onScroll event synchronously, most asynchronously. It's not consistent in IE. The code assumed it was fired synchronously. Also, ScrollBar did not apply "ideal" values (remembered) values correctly and List did not update scroll position correctly if item dimension changed.