1. #1
    Sencha Premium Member
    Join Date
    Mar 2012
    Posts
    83
    Answers
    2
    Vote Rating
    1
    scottd is on a distinguished road

      0  

    Default Unanswered: How to scroll to a selectfield's checked item?

    Unanswered: How to scroll to a selectfield's checked item?


    I have a selectfield that contains more than 100 items. When the page is starting up, I call selectfield.setValue(record) to select a particular item. When I click the selectfield to display the list, though, it is scrolled to the top, so my 'selected' item is not visible unless I've selected something within the first 8 elements.

    How do I scroll to the item represented by selectfield.getValue()?

    I've tried a couple of methods from the web related to List itself, but none of them even remotely worked. None of them reference the List within a selectfield. I've tried hacking around with selectfield.getTabletPicker() and other stuff, but to no avail.

    All I want to do is have the List scroll to the item that I've programmatically selected. Sencha doesn't support this natively, and I'm growing increasingly frustrated with the scant documentation. How do I do this?

  2. #2
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    36,604
    Answers
    3450
    Vote Rating
    818
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      1  

    Default


    When the list is shown you can use the list.getScrollable().getScroller().scrollTo(x, y). To get the x,y you need to get the view item of the list based on the index of the selected record via list.getItemAt(index). Then you can get the y position of that .
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Forum Manager
    ________________
    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

  3. #3
    Sencha Premium Member
    Join Date
    Mar 2012
    Posts
    83
    Answers
    2
    Vote Rating
    1
    scottd is on a distinguished road

      0  

    Default


    Quote Originally Posted by mitchellsimoens View Post
    When the list is shown you can use the list.getScrollable().getScroller().scrollTo(x, y). To get the x,y you need to get the view item of the list based on the index of the selected record via list.getItemAt(index). Then you can get the y position of that .
    Thanks, Mitchell, but this doesn't get me past the issue of finding out the Y position of the element.

    I'm using a selectField, which contains a list. I select an item with selectField.setValue(). There is no 'selected item' that I can find, because selectField.getSelected() relates to the text in the input field - not the selected item in the list.

    I can find the selected record with sf.getRecord(), and I can query the store for the index of that element. Let's say that the index is 116. How do I access item 116 within the selectField's list? Do I need to access the picker directly?

    // Get access to the dropdown's list component
    var listPanel = selectField.getTabletPicker();
    var list = listPanel.down('list');

    - The picker doesn't have a getItemAt() method, and the picker's list element's getItemAt() returns NULL.
    - I don't know how to actually access the 'checked' item, and the documentation isn't helping.
    - If I call list.getItems(), it returns a class instead of an array of items.

  4. #4
    Sencha Premium Member
    Join Date
    Mar 2012
    Posts
    83
    Answers
    2
    Vote Rating
    1
    scottd is on a distinguished road

      0  

    Default


    Quote Originally Posted by mitchellsimoens View Post
    When the list is shown you can use the list.getScrollable().getScroller().scrollTo(x, y). To get the x,y you need to get the view item of the list based on the index of the selected record via list.getItemAt(index). Then you can get the y position of that .
    There are an absurd number of properties and classes in the object returned from list.getItemAt(index). Which property or API of this obscene list is the item's simple Y position? These APIs are so convoluted.

  5. #5
    Sencha Premium Member
    Join Date
    Jul 2012
    Posts
    95
    Vote Rating
    3
    grizzly21 is on a distinguished road

      0  

    Default


    I think this should be the default behaviour out of the box for the select field: when opening the picker it should automatically scroll to the selected item.

  6. #6
    Sencha Premium Member
    Join Date
    Jul 2012
    Posts
    95
    Vote Rating
    3
    grizzly21 is on a distinguished road

      0  

    Default override

    override


    I've written an override that does this, I don't like the settimeout/requestanimframe at the end of it, so it would be better if sencha developers implemented it nicer.

    Code:
    Ext.define('SelectFieldOverrideForAutoSelect', {
        override: 'Ext.field.Select',
        showPicker: function() {
            var store = this.getStore();
            //check if the store is empty, if it is, return
            if (!store || store.getCount() === 0) {
                return;
            }
    
    
            if (this.getReadOnly()) {
                return;
            }
    
    
            this.isFocused = true;
    
    
            if (this.getUsePicker()) {
                var picker = this.getPhonePicker(),
                    name   = this.getName(),
                    value  = {};
    
    
                value[name] = this.getValue();
                picker.setValue(value);
                if (!picker.getParent()) {
                    Ext.Viewport.add(picker);
                }
                picker.show();
            } else {
            	
            	// used below
            	var firstTime = !this.listPanel;
            	
                var listPanel = this.getTabletPicker(),
                    list = listPanel.down('list'),
                    index, record;
    
    
                store = list.getStore();
                index = store.find(this.getValueField(), this.getValue(), null, null, null, true);
                record = store.getAt((index == -1) ? 0 : index);
    
    
                if (!listPanel.getParent()) {
                    Ext.Viewport.add(listPanel);
                }
    
    
                listPanel.showBy(this.getComponent(), (Ext.os.is.BlackBerry && Ext.os.version.getMajor() === 10) ? 't-b' : null);
                list.select(record, null, true);
                
                var firstSelected = list.getSelection()[0];
                var store = list.getStore();
                
                if (firstSelected && store) {
                	
                	var itemHeight = (list.getItemHeight() || 47);
                	var selectedIndex = store.data.items.indexOf(firstSelected);
                	
                	var scroller = list.getScrollable().getScroller();
                	
                	var scrollToX = scroller.position.x;
                	var scrollToY = itemHeight * selectedIndex;
                	
                	// center selection vertically (otherwise it appears on the top)
                	var scrollerHeight = list.getScrollable().getScroller().getElement().dom.clientHeight;
                	scrollToY -= (scrollerHeight - itemHeight)/2;
                	
               		// scroll it: first time the listPanel is not yet created,
               		// so scroll is not working (->delay)
                	if (firstTime) {
                		if (requestAnimationFrame) {
                			requestAnimationFrame(updateScroll);
               	 		} else {
                			setTimeout(updateScroll, 300);
                		}
                	} else {
                		updateScroll();
                	}
                }
                            
                function updateScroll() {
                	scroller.scrollTo(scrollToX, scrollToY);
                }
            }
        }            
    });

  7. #7
    Sencha Premium Member
    Join Date
    Jul 2012
    Posts
    95
    Vote Rating
    3
    grizzly21 is on a distinguished road

      0  

    Default override for 2.3

    override for 2.3


    Actually, this is a bit better, and it's for sdk 2.3

    Code:
    Ext.define('SelectFieldOverrideForAutoScrollToSelection', {
        override: 'Ext.field.Select',
    	showPicker: function() {
    		var me = this,
    			store = me.getStore(),
    			value = me.getValue();
    
    
    		//check if the store is empty, if it is, return
    		if (!store || store.getCount() === 0) {
    			return;
    		}
    
    
    		if (me.getReadOnly()) {
    			return;
    		}
    
    
    		me.isFocused = true;
    
    
    		if (me.getUsePicker()) {
    			var picker = me.getPhonePicker(),
    				name = me.getName(),
    				pickerValue = {};
    
    
    			pickerValue[name] = value;
    			picker.setValue(pickerValue);
    
    
    			if (!picker.getParent()) {
    				Ext.Viewport.add(picker);
    			}
    
    
    			picker.show();
    		} else {
    			var firstTime = !this.listPanel;
    			var listPanel = me.getTabletPicker(),
    				list = listPanel.down('list'),
    				index, record;
    
    
    			if (!listPanel.getParent()) {
    				Ext.Viewport.add(listPanel);
    			}
    
    
    			listPanel.showBy(me.getComponent(), null);
    
    
    			if (value || me.getAutoSelect()) {
    				store = list.getStore();
    				index = store.find(me.getValueField(), value, null, null, null, true);
    				record = store.getAt(index);
    
    
    				if (record) {
    					list.select(record, null, true);
    
    
    					// fix to scroll to selected item
    					var itemHeight = 47; //(list.getItemHeight() || 47);
    					
    					var scroller = list.getScrollable().getScroller();
    					var scrollerElementDom = scroller.getElement().dom;
    					
    					var scrollToX = scroller.position.x;
    					var scrollToY = itemHeight * index;
    					//var scrollToY = scrollerElementDom.children[index].offsetTop;
    					
    					// center selection vertically (otherwise it appears on the top)
    					var scrollerHeight = list.bodyElement.dom.clientHeight; // 389; 
    					scrollToY -= (scrollerHeight - itemHeight)/2;
    					
    					// scroll it: first time the listPanel is not yet created,
    					// so scroll is not working (->delay)
    					if (firstTime) {
    						if (requestAnimationFrame) {
    							requestAnimationFrame(updateScroll);
    						} else {
    							setTimeout(updateScroll, 300);
    						}
    					} else {
    						updateScroll();
    					}
    				}
    			}
    		}
    		
    		function updateScroll() {
    			scroller.scrollTo(scrollToX, scrollToY);
    		}
    	}
    });

Thread Participants: 2