So I'm trying to build a custom autocomplete dropdown for a text input. To do it, I am listening for the keydown event and if it's an up or down arrow press, I'm setting a $scope.arrowSelectedItem
variable to the proper one in the list. (As a side note, all the functionality works as far as selecting an item from the list that pops up. All I'm trying to do is highlight the current one that they've marked with the up/down arrows).
On the markup side, the items in the autocomplete list are output with ng-repeat
, with ng-repeat="item in itemList"
. The ng-class
expression I'm using is ng-class="{highlighted: item === arrowSelectedItem}"
. I know that the $scope.arrowSelectedItem
is being updated on each arrow press by using console.log, but for some reason the class isn't being updated to the list item properly.
What I've found is that after the first time of hitting an arrow key, if I make the text input box lose focus, then the class is added. Then if I click back in the box, move the arrow to select a different item, click out of the input box, then click back in, the class is added to the new one. I know that sounds weird, but that's what I've found.
What I'm not sure about is why the ng-class
expression isn't being evaluated on every arrow key press. Does anyone have any ideas why?
The answer here is that "raw" DOM events which fire outside of one of angular's built in directives (such as click events via ng-click etc) will not trigger a $digest cycle update. Until this happens the $scope properties will not be updated.
If you are in a position where you are listening for DOM events by using another framework, or simply using addEventListener(), you will need to let angular know about any changes by using $scope.$apply(), or by wrapping the code in a $timeout().
If you do this in your event handler, angular will trigger a new $digest cycle update for every keypress and your new scope values will propagate to the view.