5

I've written a wrapper UX control in Ext JS 2.x around Ext.Form.DateField to handle keypresses slightly differently. In particular, when the calendar is on display, I want the Tab key to select the highlighted date and move to the next form field.

I've got the key handler working – it selects the highlighted date and closes the calendar – but I can't get it to tab to the next field.

Do I have to work out what the next field is from the tab order and try to set its focus? That seems rather convoluted. Or can I fire some event to get my control to tab to the next field automatically (i.e. capture the Tab keypress in the calendar and process it, as I am doing, but then forward it to the underlying date field)?


Edit: In summary, is there an Ext (or, at least cross-platform) way to fire a keyboard event at a particular form field?

Dmitry Pashkevich
  • 13,431
  • 9
  • 55
  • 73
Matthew Strawbridge
  • 19,940
  • 10
  • 72
  • 93
  • you can use dispatchEvent(), this may be related: http://stackoverflow.com/questions/596481/simulate-javascript-key-events?lq=1 – pckill Oct 21 '12 at 11:22
  • @pckill That's certainly interesting, although from the comments it sounds as if it only works on certain browsers. Is there a more "Exty" way to achieve the same thing? – Matthew Strawbridge Oct 21 '12 at 11:29
  • I haven't worked with ExtJS, but if you know what is the next form field, couldn't you use a method like .focus() or .select() on it when pressing the `Tab` key? It would be easier to help you if you could provide some code that you used already. – micnic Oct 26 '12 at 13:36
  • @micnic I know the field that should be tabbed away from, but not the next one (since the datefield is a component that can be embedded in any page). I could probably work out the next field manually, but it would be difficult to get it to work with custom tab orders. I'd rather just get the original text field to handle the tab in the normal way. But I'm having problems trapping the message in the calendar panel but getting it subsequently processed by the textbox control related to it. – Matthew Strawbridge Oct 26 '12 at 19:35

1 Answers1

6

Approach I. Just don't do event.preventDefault() in your keypress/keyup event handler so you don't block the browser from performing the default action, i.e. tab-navigation. This example works:

Ext.create('Ext.form.Panel', {
    title: 'Contact Info',
    width: 300,
    renderTo: Ext.getBody(),
    items: [{
        xtype: 'textfield',
        name: 'name',
        fieldLabel: 'Name',
        listeners: {
            specialkey: function(me, e) {
                if (e.getKey() == e.TAB) {
                        console.log('Tab key pressed!');
                        // do whatever you want here just don't do e.preventDefault() or e.stopEvent() if you want the browser tab to next control
                    }
            }
        }
    }, {
        xtype: 'textfield',
        name: 'email',
        fieldLabel: 'Email Address',
    }]
});

I tried it in Ext 4 but all the essential methods should be available since Ext 2. If you still experience issues please share some of your code.

Getting out of the way and letting the browser do its stuff natively is usually the best and the most robust solution...


Approach II. If you have a complicated component with multiple elements, you can still achieve the case of Approach I. by forcing the focus on the main input element (usually a text field) while simulating focusing items inside a popup element with CSS (a KeyNav/KeyMap in the main input element would be handy here). You just basically catch all the cases where the user may set the focus on a popup (like clicking on it) and snap the focus back to your main element.

This would still ensure the natural tab order of html elements, even if some of them are not Components. I believe that's the best way to go and worth struggling to achieve most of the time.

That's the way components like ComboBox and DatePicker work (as you can see the latter just always sets focus to the main element after the vaule is updated. The focus logic of a ComboBox is a bit more complicated. Take a look at the source code links if you're confused about how to implement it in your component, very insightful.


Approach III. Last resort. If you still need to just programmatically focus another (neighbour) field, that's relatively easy to do. Code for Ext 2.3 (didn't test it though, I was using the docs):

var formPanel,  // containing form panel
    currentField, // the field you need to navigate away from

    fields,
    currentFieldIdx,
    nextField;

fields = formPanel.getForm().items;
currentFieldIdx = fields.indexOf(currentField);

if(currentFieldIdx > -1) {
    nextField = fields.itemAt(currentFieldIdx + 1);
    nextField && nextField.focus();
}

P.S. You can artificially fire the Tab key press via dispatchEvent() but it will not trigger the tab-navigation action due to security reasons.

Community
  • 1
  • 1
Dmitry Pashkevich
  • 13,431
  • 9
  • 55
  • 73
  • +1 for the PS. Unfortunately the `datefield` has two parts: I'm trapping the Tab on the calendar but I need it to be processed by the text field. I'm not artificially stopping the event, but it never gets passed from the calendar to the text field. – Matthew Strawbridge Oct 26 '12 at 19:26
  • Thanks very much for the update. Approaches II and III look promising. I'll give them a try and report back (probably not until Monday). – Matthew Strawbridge Oct 26 '12 at 22:19
  • I got it working using Approach III. Because I'm working on a component, I had to resort to some standard Javascript DOM traversal to find the next `input`, `option`, `button` or `textarea` from the current one, and then focus it with a slight delay. Thanks for helping me to get there. – Matthew Strawbridge Oct 29 '12 at 20:25
  • You're welcome. Keep in mind that this approach isn't bulletproof as it's practically difficult to catch **all** dom elements that can be focusable (and preserve their tab-order). Any element with a `tabindex` attribute can be focused. It may not matter in your case but just keep in mind that artificially achieved navigation may differ from the "natural", browser-implemented. That's why I was suggesting the Approach II whenever possible. – Dmitry Pashkevich Oct 29 '12 at 21:52