15

Is there a cleaner way of delegating focus to an element when a checkbox is clicked. Here's the dirty version I hacked:

HTML

<div ng-controller="MyCtrl">
    <input type="checkbox" ng-change="toggled()">
    <input id="name">
</div>

JavaScript

var myApp = angular.module('myApp',[]);

function MyCtrl($scope, $timeout) {
    $scope.value = "Something";
    $scope.toggled = function() {
        console.debug('toggled');
        $timeout(function() {
            $('#name').focus();
        }, 100);
    }
}

JSFiddle: http://jsfiddle.net/U4jvE/8/

Daan
  • 7,685
  • 5
  • 43
  • 52
kolrie
  • 12,562
  • 14
  • 64
  • 98

4 Answers4

17

how about this one ? plunker

 $scope.$watch('isChecked', function(newV){
      newV && $('#name').focus();
    },true);

@asgoth and @Mark Rajcok are correct. We should use directive. I was just lazy.

Here is the directive version. plunker I think one good reason to make it as directive is you can reuse this thing.

so in your html you can just assign different modals to different sets

<input type="checkbox" ng-model="isCheckedN">
<input xng-focus='isCheckedN'>


directive('xngFocus', function() {
    return function(scope, element, attrs) {
       scope.$watch(attrs.xngFocus, 
         function (newValue) { 
            newValue && element.focus();
         },true);
      };    
});
maxisam
  • 21,975
  • 9
  • 75
  • 84
7

Another directive implementation (that does not require jQuery), and borrowing some of @maxisam's code:

myApp.directive('focus', function() {
    return function(scope, element) {
       scope.$watch('focusCheckbox', 
         function (newValue) { 
            newValue && element[0].focus()
         })
    }      
});

HTML:

<input type="checkbox" ng-model="focusCheckbox">
<input ng-model="name" focus>

Fiddle.

Since this directive doesn't create an isolate scope (or a child scope), the directive assumes the scope has a focusCheckbox property defined.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • @maxisam, I like the attribute you added in your answer. BTW, does element.focus() work for you? I had to use element[0].focus(). – Mark Rajcok Dec 29 '12 at 02:58
  • I forgot you are including jQuery, so that's why element.focus() works. If jQuery isn't included, we have to use element[0].focus() instead. – Mark Rajcok Dec 29 '12 at 03:48
5

If you want to make it more interesting, and support for any expression to be evaluated (not only variables), you can do this:

app.directive('autofocusWhen', function ($timeout) {
    return {
        link: function(scope, element, attrs) {
            scope.$watch(attrs.autofocusWhen, function(newValue){
                if ( newValue ) {
                    $timeout(function(){
                        element.focus();
                    });
                }
            });
        }
     };
});

And your html can be a little more decoupled, like that:

<input type="checkbox" ng-model="product.selected" />
{{product.description}}
<input type="text" autofocus-when="product.selected" />
ViniciusPires
  • 983
  • 3
  • 12
  • 26
  • 1
    Why did you use the $timeout service? – Alpha Jun 08 '14 at 01:28
  • 1
    @Alpha, for some reason, in AngularJS, `$watch` expressions happen before the html re-draw, so a instant call to `element.focus();` would focus the element and immediately lose the focus, as the scope change, and the element is redrawed. Using the `$timeout` service is a known workaround for adding the change in the queue, so it happens right after the HTML redraw. – ViniciusPires Jul 30 '14 at 01:41
0

A cleaner way is to use a directive to perform the toggle:

app.directive('toggle', function() {
   return {
      restrict: 'A',
      scope: {
         selector: '='
      },
      link: function(scope, element, attrs) {
          element.on('change', function() {
              $(scope.selector).focus();
              scope.$apply();
          });
      }
   }:
});

Your html would be sth like:

<input type='checkbox' toggle selector='#name'>
asgoth
  • 35,552
  • 12
  • 89
  • 98
  • What if the selector is not unique on the page? In this case I would have many `.name`s but only one of them matches the current scope. – kolrie Dec 29 '12 at 00:37