angularjsangular-ui-bootstrapangular-ui-gridangular-ui-typeahead

Using typeahead in AngularJS UI-grid with cellNav


I have an Angular-UI grid defined with ui-grid-cellNav to allow editing cells when single-clicked, along with a custom template to display an Angular-UI Bootstrap typeahead to a particular column as below:

index.html:

<head>
  <script type="text/ng-template" id="TypeaheadTemplate.html">
      <div style="height:100%">
        <input ng-class="'colt' + col.uid" type="text" class="typeahead form-control" ng-model="MODEL_COL_FIELD"
           uib-typeahead="name as item.name for item in grid.appScope.items | filter:$viewValue"
           typeahead-editable="false"
           typeahead-on-select="grid.appScope.typeaheadSelected(row.entity, $item)"></input>
       </div>
  </script>
</head>

<body ng-controller="MainCtrl">
    <div ui-grid="gridOptions" ui-grid-edit ui-grid-cellNav></div>
</body>

controller.js

app.controller('MainCtrl', function($scope) {
  $scope.items = [
    {
      id: 1,
      name: "Item 1",
      description: "Example Item #1"
    },
    {
     id: 2,
     name: "Item 2",
     description: "Example Item #2"
    }];

    $scope.data = [{}, {}, {}]

    $scope.columns = [
      {
        displayName: "Item",
        field: "item.name",
        editableCellTemplate: "TypeaheadTemplate.html",
        cellTemplate: "TypeaheadTemplate.html",
        enableCellEdit: true,
        enableCellEditOnFocus: true
      },
      {
        displayName: "Note",
        name: "activityId",
        enableCellEdit: true,
        enableCellEditOnFocus: true
      }]

    $scope.gridOptions = {
      data: $scope.data,
      enableRowSelection: false,
      showColumnFooter: true,
      multiSelect: false,
      enableSorting: false,
      enableFiltering: false,
      gridMenuShowHideColumns: false,
      enableColumnMenus: false,
      enableCellEditOnFocus: true,
      minRowsToShow: 4,
      columnDefs: $scope.columns
    };

    $scope.typeaheadSelected = function(entity, selectedItem) {
      entity.item = selectedItem;
    }
});

Example Plunker

This works well enough, with ui-grid-cellNav allowing single-click editing on the Notes column and the typeahead functioning in the Items column. However, initially clicking a typeahead textbox in the grid blurs the textbox until it's clicked again, and keeping a cell in Notes selected (but not editable) will often prevent the textbox from being selected. So, while it's functional, it's got some usability issues.

I've already tried manually applying the class to the textbox by using the ng-class attribute, thinking there was some logic behind-the-scenes which focused elements with this class, but to no avail. I also can't find anything in the API documentation which suggests being able to override cellNav behaviour for a given column. Removing the ui-grid-cellNav directive fixes typeahead focusing, but also breaks single-click editing.

Is there any way to make typeaheads in an Angular-UI grid play nicely with ui-grid-cellNav?


Solution

  • You can set allowCellFocus to false for any columns with typeaheads inside, and this will ensure that ui-grid-cellNav doesn't take focus away from the typeahead textbox initially. One caveat to note is the typeahead textbox will still require two clicks when a cellNav cell already has focus, and this will mess up tab-indexing on the rest of your grid.

    $scope.columns = [
      {
        displayName: "Item",
        field: "item.name",
        allowCellFocus: false, // Property added here
        editableCellTemplate: "TypeaheadTemplate.html",
        cellTemplate: "TypeaheadTemplate.html",
        enableCellEdit: true,
        enableCellEditOnFocus: true
      },
      // ...
    ];
    

    Updated Plunker

    If possible, you should consider using a ui-select drop-down in place of the typeahead. These behave much more reliably in a grid with cellNav, however you will still need to account for messed up tab-index behavior.