I was playing around with my trusty multi-select dropdown earlier today and a colleague of mine pointed out that changing the selected items outside of the directive would not actually deselect previously selected items. This was a curious bug since I knew I had a watcher on the ngModel selections.
Setting the selected items on first load always worked without a hitch. But I found that I had put in some conditional logic that was not firing the “mark checked” code that I had in place. The “mark checked” code would simply iterate over all of the internal items and compare their values to ngModel, whether it was simple scalar or complex object, and set the checked property. The comparison itself wasn’t comparing apples to apples, though, and nothing was being checked. Additionally, clearing out ngModel did nothing. Finally, since ngModel would change inside of the directive itself when calling modelCtrl.$setViewValue, I wanted to avoid the looping over the items and ngModel array unnecessarily.
I won’t post a ton of code here showing the changes, but suffice it to say there is a bit set when the directive itself has triggered a change to the ngModel. When this bit is set, the iterative code that sets the checkmarks is not called when the ngModel watcher is triggered. Conversely, if an external process updates ngModel, the code will fire to compare the new selection vs. the available items and mark them as checked or unchecked appropriately.
The updated demo shows how randomly setting the selected items or clearing the selecting items stored in ngModel will now be properly handled by the directive.