Reputation: 2027
So I have a variable number of input fields and after saving them I'd like to return focus to the first of them.
HTML Code:
<td ng-repeat='col in list.cols'>
<input class='colData' type='text' ng-model='newentry[$index]' on-press-enter="addRow(newentry)">
</td>
As you can probably read I call 'addRow()' when pressing enter and then add the values to my data model. This works fine.
Now after adding the data I would like to set the focus to the first of these input fields.
I am trying to resist the urge to fall back on my jQuery knowledge. If i included jQuery I could just do $('input.colData').first().focus();
.
But I'm really trying to learn to do things 'the angular way'.
How would I approach this scenario?
Is there a way maybe to select an input field by the model it contains?
thanks,
J
UPDATE: I don't think this is a duplicate, as in my case I can't add a directive to the input field, as they are created dynamically by angular and only the first one should be focussed. Their number is, as stated above, variable. I fail to see how to identify the first among them aside from the jQuery one-liner.
Upvotes: 1
Views: 3547
Reputation: 3254
How to focus the first element using a directive after a submission of a form? The following assumptions were made:
For a demonstration, please see this jsFiddle. Let me know if I have understood your problem properly.
The controller will contain the code for managing your data or submitting your resource to the server. It will then broadcast an event that data has been submitted. Since no code was provided in the original post, I've taken the liberty of filling in the gaps.
Alternatively, a $promise
could be used to trigger the event which would provide a means to handle any server issues.
function ctrl($scope) {
$scope.items = [ 'thing 1', 'thing 2', 'thing 3' ];
$scope.data = [];
$scope.addRow = function(newEntry) {
var entry = newEntry || 'thing ' + $scope.items.length + 1;
$scope.$evalAsync(function() {
$scope.items.push(entry);
});
};
$scope.submit = function() {
console.log("Simulating a submit");
$scope.$broadcast("formSubmitted");
};
}
The directive will respond to the event by focusing the first element. The post-link is used to initialize the events and setup the listeners for the event. When the event is triggered, the element will be focused. This creates a clear separation of data and presentation.
function onPressEnter() {
return {
restrict : 'A',
scope: {
onPressEnter: '&'
},
link: function($scope, $element, $attr, $ctrl) {
$element.on('keyup', function(e) {
if (e.which === 13) {
$scope.onPressEnter();
}
});
$scope.$on("formSubmitted", function() {
if ($scope.$parent.$first) {
$element[0].focus();
}
});
}
}
};
Alternatively, you can isolate this directive as a reusable component and use the following. All you would have to do is add on-submit-focus="0"
to any element to have it focus on its first child. on-submit-focus="1"
would select the second child, and so on... An updated demonstration is available here.
function onSubmitFocus() {
return function($scope, $element, $attr) {
$scope.$on('formSubmitted', function() {
if ($scope.$index === +$attr.onSubmitFocus) {
$element.children()[0].focus();
}
});
};
}
Upvotes: 2
Reputation: 2238
You can check for the first element and apply the attribute "autofocus" in that case
<td ng-repeat='col in list.cols'>
<input class='colData' type='text' ng-model='newentry[$index]' on-press-enter="addRow(newentry)" ng-if="$first" autofocus>
<input class='colData' type='text' ng-model='newentry[$index]' on-press-enter="addRow(newentry)" ng-if="!$first">
</td>
Upvotes: 1