3

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?

4
  • Written descriptions are never a good replacement for actual code when diagnosing these things. It sounds to me like you might be listening for the keypress outside of angular's $digest cycle and not informing the framework of it in your event handler, for example by calling $scope.$apply(). Happy to take another look if you post some code though Commented Oct 12, 2015 at 20:01
  • @JamesHenry Sorry about that. Here's a gist with the applicable code. Commented Oct 12, 2015 at 20:05
  • @JamesHenry Thanks for the suggestion. Turned out to be the answer. I just had to add $scope.$apply() at the end of my keyHandler function. Thanks again for the help! Commented Oct 12, 2015 at 20:08
  • Great, if you don't mind I'll stick it in as a proper answer and you can accept it so that others may benefit if they find this post. Commented Oct 12, 2015 at 20:10

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.