PDA

View Full Version : Setting focus to a combo box?



gskluzacek
8 Mar 2010, 6:30 PM
I have a simple Ext JS html page that has a text field, a combo box and another text field in that order. When the page finishes loading I want the combo box to have focus.

For this issue and the example I render the widgets to div tags, but in my actual application they are in a toolbar, but the behavior is the same. The example page can be run at http://dev.comicbookupcdb.com/combofocus.html.

I tried what I thought was logical, to call the focus() method on the combo box at the end of the Ext.onReady() function. What happens when I do this is that the combo box gets focus but the dropdown list is expanded. I want the combo box to get focus with the drop down list collapsed.

What I'm finding is that I'm having to put the call to the focus() method in the load event for the JsonStore that is the store for the combo box. Is this the right way to do this?

But what I really want to know is why?! :-/

I did some simple investigation before coming to the above conclusion by place console.log() function calls in various places: at the end of onReady, in the combo box's render and after render events and in the data store's load event. The order that I saw the output in the console was:
Render event After Render event end of the OnReady() function Load Event.


So it would appear that the load event is firing last and if the combo box has focus before the data store has loaded, it causes the dropdown list to expand?

HTML Code

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Greg Test Page</title>
<link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css">
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext/ext-all-debug.js"></script>

<script type="text/javascript">
Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif';

Ext.onReady(function() {

var pubComboDs = new Ext.data.JsonStore({
url: 'data/publishers.json',
root: 'rows',
totalProperty: 'results',
idProperty: 'pub_id',
fields: [ {name: 'pub_id', type: 'int'}, 'name' ],
autoLoad: true,
listeners: {
'load' : { fn: function(store, records, options) {
console.log('loaded');
combo.focus();
}}
}
});

var combo = new Ext.form.ComboBox({
renderTo: 'combo',
store: pubComboDs,
displayField:'name',
valueField: 'pub_id',
mode: 'local',
forceSelection: true,
triggerAction: 'all',
emptyText: 'Select a Publisher...',
selectOnFocus: true,
id: 'pub_combo',
typeAhead: true,
resizable: true,
width: 175,
listeners: {
'render' : { fn: function(comp) {
console.log('rendered');
// comp.focus();
}},
'afterrender' : { fn: function(comp) {
console.log('afterrenred');
// comp.focus();
}}
}
});

var text1 = new Ext.form.TextField({
renderTo: 'text1',
id: 'text_field1',
width: 175
});

var text2 = new Ext.form.TextField({
renderTo: 'text2',
id: 'text_field2',
width: 175
});

// text1.focus();
console.log('end of onReady');
// combo.focus();

});

</script>

</head>
<body>

<div id="text1" style="padding: 15px 0px 0px 15px;"></div>
<div id="combo" style="padding: 15px 0px 0px 15px;"></div>
<div id="text2" style="padding: 15px 0px 0px 15px;"></div>

</body>
</html>


JSON Record Set

{"success":true,
"results":100,
"rows":[
{"pub_id":"7","name":"AC"},
{"pub_id":"9","name":"Acclaim"},
{"pub_id":"8","name":"ADV Manga"},
{"pub_id":"10","name":"Adventure"},
{"pub_id":"12","name":"Aircel"},
{"pub_id":"11","name":"AiT\/Planet Lar"},
{"pub_id":"13","name":"Alias"},
{"pub_id":"14","name":"Alternative"},
{"pub_id":"15","name":"Antarctic"},
{"pub_id":"16","name":"Arcana"},
{"pub_id":"17","name":"Archie"},
{"pub_id":"18","name":"Aspen"},
{"pub_id":"19","name":"Avalon"},
{"pub_id":"20","name":"Avatar"},
{"pub_id":"21","name":"Avon"},
{"pub_id":"22","name":"Blackthorne"},
{"pub_id":"23","name":"Boneyard"},
{"pub_id":"24","name":"Boom!"},
{"pub_id":"25","name":"Brainstorm"},
{"pub_id":"29","name":"Caliber"},
{"pub_id":"30","name":"Chaos"},
{"pub_id":"31","name":"Charlton"},
{"pub_id":"26","name":"CMX"},
{"pub_id":"27","name":"COMICO"},
{"pub_id":"32","name":"ComicsOne"},
{"pub_id":"28","name":"CPM"},
{"pub_id":"33","name":"CrossGen"},
{"pub_id":"34","name":"Crusade"},
{"pub_id":"35","name":"D.C. Thomson"},
{"pub_id":"2","name":"Dark Horse"},
{"pub_id":"1","name":"DC"},
{"pub_id":"38","name":"Del Rey"},
{"pub_id":"39","name":"Dell"},
{"pub_id":"40","name":"Devil\u2019s Due"},
{"pub_id":"41","name":"Digital Manga"},
{"pub_id":"42","name":"Disney"},
{"pub_id":"43","name":"Drawn and Quarterly"},
{"pub_id":"44","name":"Dupuis"},
{"pub_id":"45","name":"Dynamite"},
{"pub_id":"46","name":"E.C."},
{"pub_id":"47","name":"Eclipse"},
{"pub_id":"48","name":"Entity"},
{"pub_id":"49","name":"Epic"},
{"pub_id":"50","name":"Eros"},
{"pub_id":"51","name":"Eternity"},
{"pub_id":"3","name":"Fantagraphics"},
{"pub_id":"53","name":"Fawcett"},
{"pub_id":"54","name":"First"},
{"pub_id":"55","name":"Fleetway Quality"},
{"pub_id":"56","name":"Fox"},
{"pub_id":"57","name":"Gemstone"},
{"pub_id":"58","name":"Gold Key"},
{"pub_id":"60","name":"Harris"},
{"pub_id":"61","name":"Harvey"},
{"pub_id":"62","name":"Heavy Metal"},
{"pub_id":"59","name":"HM Communications"},
{"pub_id":"63","name":"Humanoids"},
{"pub_id":"65","name":"Idea + Design Works"},
{"pub_id":"4","name":"Image"},
{"pub_id":"67","name":"Innovation"},
{"pub_id":"64","name":"IPC"},
{"pub_id":"68","name":"Kitchen Sink"},
{"pub_id":"69","name":"Last Gasp"},
{"pub_id":"70","name":"Lightning"},
{"pub_id":"71","name":"London Night"},
{"pub_id":"73","name":"Malibu"},
{"pub_id":"5","name":"Marvel"},
{"pub_id":"75","name":"Marvel UK"},
{"pub_id":"76","name":"Millennium"},
{"pub_id":"77","name":"Mirage"},
{"pub_id":"78","name":"Moonstone"},
{"pub_id":"72","name":"MU"},
{"pub_id":"79","name":"NBM"},
{"pub_id":"80","name":"NEC"},
{"pub_id":"81","name":"Now"},
{"pub_id":"82","name":"Oni"},
{"pub_id":"83","name":"Panini"},
{"pub_id":"84","name":"Parody Press"},
{"pub_id":"85","name":"Quality"},
{"pub_id":"86","name":"Radio Comix"},
{"pub_id":"87","name":"Re-Visionary"},
{"pub_id":"88","name":"Rebellion"},
{"pub_id":"89","name":"Rip Off"},
{"pub_id":"90","name":"Sirius"},
{"pub_id":"91","name":"Slave Labor"},
{"pub_id":"92","name":"St. John"},
{"pub_id":"93","name":"Standard"},
{"pub_id":"94","name":"Titan"},
{"pub_id":"95","name":"Tokyopop"},
{"pub_id":"96","name":"Tome"},
{"pub_id":"97","name":"Top Shelf"},
{"pub_id":"98","name":"Topps"},
{"pub_id":"99","name":"Tundra"},
{"pub_id":"100","name":"TwoMorrows"},
{"pub_id":"101","name":"Valiant"},
{"pub_id":"102","name":"Verotik"},
{"pub_id":"103","name":"Vertigo"},
{"pub_id":"6","name":"Viz"},
{"pub_id":"105","name":"WildStorm"},
{"pub_id":"106","name":"Wizard"}
]}

tobiu
8 Mar 2010, 11:04 PM
explaining the why should be easy: ajax.

your script gets executed, your json-store fires a request to the server (autoLoad:true), which takes much longer than the execution-time of the script. when the response arrives with the data of the combo, the store adds the records and the dataView behind the combo is rendered. the load-event fires.


kind regards,
tobiu

gskluzacek
9 Mar 2010, 2:35 PM
OK, the order of the firing of the various events... yes, I agree is the nature of asynchronous processing (the A in Ajax).

But that still doesn't answer my real questions :">

What is causing the combo box's drop down list to expand? Seams related to the fact that the combo box's data store hasn't finished loading yet... though I would think as long as the combo box has been rendered that it wouldn't matter.

And is calling the combo box's focus() method in it's data store load event listener the correct way to give the combo box focus?

Thanks and Regards,
-- Greg

tobiu
9 Mar 2010, 2:54 PM
i took a look into the source of the combo:



// private
onLoad : function(){
if(!this.hasFocus){
return;
}
if(this.store.getCount() > 0 || this.listEmptyText){
this.expand();
this.restrictHeight();
if(this.lastQuery == this.allQuery){
if(this.editable){
this.el.dom.select();
}

if(this.autoSelect !== false && !this.selectByValue(this.value, true)){
this.select(0, true);
}
}else{
if(this.autoSelect !== false){
this.selectNext();
}
if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
this.taTask.delay(this.typeAheadDelay);
}
}
}else{
this.collapse();
}

}



kind regards,
tobiu