I have places in my code where I have this:
<input data-ng-disabled="SOME_SCOPE_VARIABLE" />
I would like to be able to use it like this too:
<input data-ng-autofocus="SOME_SCOPE_VARIABLE" />
Or even better, mimicking how ng-style is done:
<input data-ng-attribute="{autofocus: SOME_SCOPE_VARIABLE}" />
Does this exist in the current version of angular? I noticed in the code there's a BOOLEAN_ATTR which gets all the attr's that angular supports. I don't want to modify that in fear of changing versions and forgetting to update.
Update: AngularJS now has an ngFocus directive that evaluates an expression on focus, but I mention it here for the sake of completeness.
The current version of AngularJS doesn't have a focus directive, but it's in the roadmap. Coincidentally, we were talking about this on the mailing list yesterday, and I came up with this:
angular.module('ng').directive('ngFocus', function($timeout) {
return {
link: function ( scope, element, attrs ) {
scope.$watch( attrs.ngFocus, function ( val ) {
if ( angular.isDefined( val ) && val ) {
$timeout( function () { element[0].focus(); } );
}
}, true);
element.bind('blur', function () {
if ( angular.isDefined( attrs.ngFocusLost ) ) {
scope.$apply( attrs.ngFocusLost );
}
});
}
};
});
Which works off a scope variable as you requested:
<input type="text" ng-focus="isFocused" ng-focus-lost="loseFocus()">
Here's a fiddle: http://jsfiddle.net/ANfJZ/39/
I did it with two custom directives, something like this:
(function(angular) {
'use strict';
/* @ngInject */
function myAutoFocus($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
$timeout(function() {
element[0].focus();
}, 300);
}
};
}
function myFocusable() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var focusMethodName = attrs.myFocusable;
scope[focusMethodName] = function() {
element[0].focus();
};
}
};
}
angular
.module('myFocusUtils', [])
.directive('myAutoFocus', myAutoFocus)
.directive('myFocusable', myFocusable);
}(angular));
If you add attribute my-auto-focus to an element, it will receive focus after 300ms. I set the value to 300 instead of 0 to let other async components to load before setting the focus.
The attribute my-focusable will create a function in the current scope. This function will set focus to the element when called. As it creates something in the scope, be cautious to avoid overriding something.
This way you don't need to add something to Angular's digest cycle (watch) and can do it entirely in the view:
<input my-focusable="focusOnInput"></input>
<button ng-click="focusOnInput()">Click to focus</button>
I created a JSFiddle to show the myFocusable directive: http://jsfiddle.net/8shLj3jc/
For some reason I don't know, the myAutoFocus directive does not work in JSFiddle, but it works in my page.
This directive should do the trick:
angular.module('utils.autofocus', [])
.directive('autofocus', ['$timeout', function($timeout) {
return {
restrict: 'A',
scope: {'autofocus':'='}
link : function($scope, $element) {
$scope.$watch 'autofocus', function(focus){
if(focus){
$timeout(function() {
$element[0].focus();
});
}
}
}
}
}]);
Taken from here: https://gist.github.com/mlynch/dd407b93ed288d499778
What I did is using regular autofocus on my inputs: <input autofocus>
And then I set the focus on the first visible input with autofocus when angular is ready:
angular.element(document).ready(function() {
$('input[autofocus]:visible:first').focus();
});
Hope this helps.