2

Suppose I have a component like this

app.component('test',{
    template: '<input type="text" id="inputbox"></input>',
    controller: function() {
        ctrl.focusInput = function(){
                var inputbox = document.getElementById("inputbox");
                inputbox.focus();
            }
        };
    }    
});

I would like to get the DOM element for the input so I can focus it whenever I want. However inputbox falls in global scope which will be a problem if I use this component more than once. How can I get the DOM just for the input in this component - either by restricting scope of inputbox or using some other mechanism?

5
  • 2
    controller: ['$element', function($element) { Commented Mar 14, 2017 at 12:23
  • stackoverflow.com/questions/25633139/… Commented Mar 14, 2017 at 12:23
  • @PetrAveryanov so what would the var inputbox line look like with your suggestion? Commented Mar 14, 2017 at 12:27
  • @Daniel_L that seems to solve the opposite problem, triggering functions on focus not focus from a function? Commented Mar 14, 2017 at 12:28
  • To avoid the ID problem, remove the ID and tag it with a class, even just a dummy empty one, and select on that using querySelector or $element. Note that in Angular 1, where we didn't have template ref vars, this was the "recommended" internal practice. In general I was told never to use IDs, use classes, even dummy ones. I hated doing it but it did solve the problem. Commented Mar 14, 2017 at 12:33

1 Answer 1

4

You could inject the element that triggered the component to controller function like below:

Since $element is jqLite wrapped object, you can use jQuery DOM traversal methods like children and find to find the input element.

angular
  .module('myApp', []);
angular
  .module('myApp').component('test', {
    template: '<input type="text" id="inputbox"></input>',
    controller: function($scope, $element, $attrs) {
      var ctrl = this;
      ctrl.focusInput = function() {
        $timeout(function() {
          $element.find('input').focus();
        }, 0);
      };
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>

<div ng-app="myApp">
  <test></test>
</div>

Sign up to request clarification or add additional context in comments.

7 Comments

this method looks ok, but i suspect that this is a good practise. if we need DOM to make manipulations, why not isolate scope directive with all that code in link function? answer to the question is perfect though.
This seems to fail when I test document.activeElement===$element.children().find('input') to determine if the input is focussed already - is that because the DOM element is wrapped in something else?
Also I'm getting undefined for $element.children().find('input')?
The real document has input nested in a div but still $element.find(".myinputclass") or $element.find("input") should find it right?
Ok so I had to wrap the call to focus in a $timeout(). Not quite sure why. The DOM should have been rendered already so the focus method should be available all along...
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.