Question

What is the best way in Angular to put focus on a textbox following an event, i.e. a button click?

Here is my scenario: Our app has a page with a table displaying customer data. The first column in each row has an 'Edit' button. When clicked the data in all other columns turn into editable textboxes. Next I need to put focus on the first textbox, which is the name of the customer.

Any assistance is appreciated.

2 Answers

The HTML view can be either in two modes. Initially, it is in 'display' mode and the customer records are displayed in an HTML table in non-edit (read-only) mode. In each row, there is a Edit button which when clicked toggles the row to 'edit' mode and the input text boxes are displayed for each cell. Instead of the Edit button, the Save and Cancel buttons are then displayed. The Cancel button discards the changes made by the user in 'edit' mode while the Save button accepts those changes and in both the cases, the user is taken back to the 'display' mode.

Notice the presence of two scripts in the HTML view with the ids named 'edit' and 'display' and they are executed depending upon when the user clicks the Edit or Save/Cancel buttons respectively.

<div ng-app="app" ng-controller="AppCtrl">
   <table>
       <thead>
           <th>Customer Name</th>
           <th>Location</th>
           <th></th>
       </thead>
       <tbody>
           <tr ng-repeat="customer in model.customers" ng-include="getTemplate(customer)">
           </tr>
       </tbody>
   </table>

   <script type="text/ng-template" id="display">
       <td>{{customer.name}}</td>
       <td>{{customer.location}}</td>
       <td>
           <button ng-click="editCustomer(customer)">Edit</button>
       </td>
   </script>
   <script type="text/ng-template" id="edit">
       <td><input type="text" focus-set ng-model="model.selected.name" /></td>
       <td><input type="text" ng-model="model.selected.location" /></td>
       <td>
           <button ng-click="save($index)">Save</button>
           <button ng-click="reset()">Cancel</button>
       </td>
   </script>
</div>

var app = angular.module("app", []);

app.controller("AppCtrl", function AppCtrl($scope) {
     $scope.model = {
         customers: [{
             id: 1,
             name: "Alice",
             location: "USA"
         }, {
             id: 2,
             name: "Cathie",
             location: "UK"
         }],
         // The 'selected' object will store the customer data when it 
         // is selected to edit. Initially, it is set to null.
         selected: {}
     };

     // When the user clicks the Edit button, copy the contents of 
     // the customer to the $scope.selected object
     $scope.editCustomer = function (customer) {
         $scope.model.selected = angular.copy(customer);
     };

     // In the HTML template above, notice that that there are two script tags 
     // having the unique ids namely, display and edit. 
     // Therefore, the value that you return from this method is actually the id of the script. 
     // So when you return the 'edit', the contents of the 'edit' script will be displayed.
     $scope.getTemplate = function (customer) {
         if (customer.id === $scope.model.selected.id)
             return 'edit';
         else
             return 'display';
     };

     $scope.save = function (idx) {
         $scope.model.customers[idx] = angular.copy($scope.model.selected);
         $scope.reset();
     };

     $scope.reset = function () {
         $scope.model.selected = {};
     };
});

// Notice the presence of this directive on the first input field.

app.directive('focusSet', function() {
   return {
     link: function(scope, element, attrs) {
       scope.$watch(attrs.focusSet, function() {
             element[0].focus();
       });
     }
   };
});

You can read the source code of this third-party module. You'll learn a lot from it.

http://vitalets.github.io/angular-xeditable/

https://github.com/vitalets/angular-xeditable

There is also its jsfiddle ...

http://jsfiddle.net/NfPcH/93/