After looking for examples of how set focus elements with angular, I saw that most of them use some variable to watch for then set focus, and most of them use one different variable for each field they want to set focus. In a form, with a lot of fields, that implies in a lot of different variables.
With jquery way in mind, but wanting to do that in angular way, I made a solution that we set focus in any function using the element's id, so, as I am very new in angular, I'd like to get some opinions if that way is right, have problems, whatever, anything that could help me do this the better way in angular.
Basically, I create a directive that watch a scope value defined by the user with directive, or the default's focusElement, and when that value is the same as the element's id, that element set focus itself.
angular.module('appnamehere')
.directive('myFocus', function () {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
if (attrs.myFocus == "") {
attrs.myFocus = "focusElement";
}
scope.$watch(attrs.myFocus, function(value) {
if(value == attrs.id) {
element[0].focus();
}
});
element.on("blur", function() {
scope[attrs.myFocus] = "";
scope.$apply();
})
}
};
});
An input that needs to get focus by some reason, will do this way
<input my-focus id="input1" type="text" />
Here any element to set focus:
<a href="" ng-click="clickButton()" >Set focus</a>
And the example function that set focus:
$scope.clickButton = function() {
$scope.focusElement = "input1";
}
Is that a good solution in angular? Does it have problems that with my poor experience I don't see yet?
Another option would be to use Angular's built-in pub-sub architecture in order to notify your directive to focus. Similar to the other approaches, but it's then not directly tied to a property, and is instead listening in on it's scope for a particular key.
Directive:
angular.module("app").directive("focusOn", function($timeout) {
return {
restrict: "A",
link: function(scope, element, attrs) {
scope.$on(attrs.focusOn, function(e) {
$timeout((function() {
element[0].focus();
}), 10);
});
}
};
});
HTML:
<input type="text" name="text_input" ng-model="ctrl.model" focus-on="focusTextInput" />
Controller:
//Assume this is within your controller
//And you've hit the point where you want to focus the input:
$scope.$broadcast("focusTextInput");
You can try
angular.element('#<elementId>').focus();
for eg.
angular.element('#txtUserId').focus();
its working for me.
I prefered to use an expression. This lets me do stuff like focus on a button when a field is valid, reaches a certain length, and of course after load.
<button type="button" moo-focus-expression="form.phone.$valid">
<button type="submit" moo-focus-expression="smsconfirm.length == 6">
<input type="text" moo-focus-expression="true">
On a complex form this also reduces need to create additional scope variables for the purposes of focusing.
About this solution, we could just create a directive and attach it to the DOM element that has to get the focus when a given condition is satisfied. By following this approach we avoid coupling controller to DOM element ID's.
Sample code directive:
gbndirectives.directive('focusOnCondition', ['$timeout',
function ($timeout) {
var checkDirectivePrerequisites = function (attrs) {
if (!attrs.focusOnCondition && attrs.focusOnCondition != "") {
throw "FocusOnCondition missing attribute to evaluate";
}
}
return {
restrict: "A",
link: function (scope, element, attrs, ctrls) {
checkDirectivePrerequisites(attrs);
scope.$watch(attrs.focusOnCondition, function (currentValue, lastValue) {
if(currentValue == true) {
$timeout(function () {
element.focus();
});
}
});
}
};
}
]);
A possible usage
.controller('Ctrl', function($scope) {
$scope.myCondition = false;
// you can just add this to a radiobutton click value
// or just watch for a value to change...
$scope.doSomething = function(newMyConditionValue) {
// do something awesome
$scope.myCondition = newMyConditionValue;
};
});
HTML
<input focus-on-condition="myCondition">
I like to avoid DOM lookups, watches, and global emitters whenever possible, so I use a more direct approach. Use a directive to assign a simple function that focuses on the directive element. Then call that function wherever needed within the scope of the controller.
Here's a simplified approach for attaching it to scope. See the full snippet for handling controller-as syntax.
Directive:
app.directive('inputFocusFunction', function () {
'use strict';
return {
restrict: 'A',
link: function (scope, element, attr) {
scope[attr.inputFocusFunction] = function () {
element[0].focus();
};
}
};
});
and in html:
<input input-focus-function="focusOnSaveInput" ng-model="saveName">
<button ng-click="focusOnSaveInput()">Focus</button>
or in the controller:
$scope.focusOnSaveInput();
angular.module('app', [])_x000D_
.directive('inputFocusFunction', function() {_x000D_
'use strict';_x000D_
return {_x000D_
restrict: 'A',_x000D_
link: function(scope, element, attr) {_x000D_
// Parse the attribute to accomodate assignment to an object_x000D_
var parseObj = attr.inputFocusFunction.split('.');_x000D_
var attachTo = scope;_x000D_
for (var i = 0; i < parseObj.length - 1; i++) {_x000D_
attachTo = attachTo[parseObj[i]];_x000D_
}_x000D_
// assign it to a function that focuses on the decorated element_x000D_
attachTo[parseObj[parseObj.length - 1]] = function() {_x000D_
element[0].focus();_x000D_
};_x000D_
}_x000D_
};_x000D_
})_x000D_
.controller('main', function() {});
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>_x000D_
_x000D_
<body ng-app="app" ng-controller="main as vm">_x000D_
<input input-focus-function="vm.focusOnSaveInput" ng-model="saveName">_x000D_
<button ng-click="vm.focusOnSaveInput()">Focus</button>_x000D_
</body>
_x000D_
Edited to provide more explanation about the reason for this approach and to extend the code snippet for controller-as use.
Source: Stackoverflow.com