Jan Paepke
Jan Paepke

Reputation: 2027

Focus a certain input field in angularjs

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

Answers (2)

Pete
Pete

Reputation: 3254

Use Case

How to focus the first element using a directive after a submission of a form? The following assumptions were made:

  • Form submission is done through Ajax either through $resource or $service
  • IE 9 support is required
  • "Angular-Way" is required

For a demonstration, please see this jsFiddle. Let me know if I have understood your problem properly.

Controller

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");
    };
}

Directive

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();
                }
            });
        }
    }
};

Directive #2

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

cardeol
cardeol

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

Related Questions