Milan Novaković
Milan Novaković

Reputation: 351

How to select the DOM element from a querySelectorAll NodeList to apply focus()?

See EDITS below for most relevant new information.

Within an angular directive, I have an element that is a div. I am searching for descendents that are inputs and grabbing the first one to apply focus to.

var nodes = element[0].querySelectorAll('input, button');

I can access the input I want with nodes[0] but I can not figure out how to execute focus() call against it.

nodes[0].focus() does not work
$(nodes[0]).focus() does not work
angular.element(nodes[0]) does not work

When I print the nodelist to the console:

NodeList [ <button.yes.btn.btn-default>, <button.no.btn.btn-default> ]

When I select nodes[0] and print to console:

<button data-ng-click="showMismatchWarning = false; verifyRentalItemsMatch()" class="yes btn btn-default" type="button" answer="">

For example, that's the button I would want to apply focus() to. I just can't seem to figure out how to go from the queryselector result to executing the native html focus()


EDIT (MOST RELEVANT INFO):

Further information. I have different tabs so they're hidden. But the directive is applied on the same boolean expression isPage(x) so the DOM elements should be visible by this point in time.

<div ng-show="isPage(1)" myFocus="isPage(1)">
  <input> <--- this very first one focus() seems to work
</div>

<div ng-show=isPage(2)" myFocus="isPage(2)">
  <input> <--- this one the focus() never works
</div>

Thinking about this more it must be that the focus() is running before the DOM element is fully visible, that's why the focus() is failing. But the directive is $watching on the attributes and watches for this same expression to become true, why would it be executing before ng-show?

Here's my directive for reference.

"use strict";
angular.module('something').directive("myfocus", function() {
    return {
        link: function(scope, element, attributes) {
            scope.$watch(attributes.focuson, function(newValue) {
                if(newValue) {
                    highlightAndFocus(element[0]);
                }
            },true);

            function highlightAndFocus(node) {
                var task = $(node);
                task.focus();
                task.addClass('highlight');

                var nextInput = node.querySelector('input, button:not(#cancel)');
                nextInput.focus();
                console.log(nextInput);

            }
        }
    };
});

Upvotes: 3

Views: 3770

Answers (1)

Marat Tanalin
Marat Tanalin

Reputation: 14123

The element to focus is apparently not visible at the moment of calling focus(). Use a non-zero timeout to delay focusing or a built-in feature (if it exists) of the framework to detect the moment the element gets visible.

Alternatively, try to read the offsetWidth (or offsetHeight) property of the element to focus, to force page reflow/repaint before setting focus.

Upvotes: 1

Related Questions