In this post I’ll explain and demonstrate a directive I’ve written which allows you to use similar behaviour of the “track by” options we are given in select lists in AngularJS with radio buttons.
AngularJS does change tracking on any object which is assigned to a scope. Every time it examines our objects and looks for changes is called a “Digest Cycle”. AngularJS uses “dirty checking” to check if our objects have changed.
In an application I’m working on, all of the “screen data” (select lists, radio buttons etc) come from the server in the form of API calls. None of this data is present in the page at the time of initial load (as with all good SPAs). There is also a call which gets data the user has saved from their last visit.
Select lists are brilliant, the ng-options on a select element allow you to set whatever property is in the ng-model to either a ValueType (think string, number, boolean) or Reference Type (object). Angular does this by using the “select as” syntax in the ng-options. If you decide you want a string property in your ng-model then you’re good. If, for example, there’s already a string value existing in your model, Angular will do a string equality check, it’ll come back as true and the select list will be modified to show the item selected. However if your select list is bound to an array of objects, and the source and target objects (ng-options expression and ng-model expression) don’t reference the exact same object, they’re not going to match and your select list wont have the correct item selected. This is because AngularJS will use object (reference) equality.
Here’s a quick plnkr example I’ve created to show what’s going on…
The object referenced in your model is not the same as the object you got from your API call. They may look the same but they are not. When AngularJS does object eqaulity, what’s really happening is it’s doing reference checks. If this is unfamiliar to you then have a read here. Because we have two different objects (even though they might look identical) they’ll never be equal.
In AngularJS, you can say “ok, so there’s going to be two objects, however I don’t want you to compare the objects to determine if they’re equal, instead I’m going to choose a property for you to check eqaulity). Essentially, this would be a “value type” property (string, number, boolean) on the object. Typically a unique field like “id”.
That’s great that the AngularJS guys have thought about that, it helps us a lot.
Unfortunately, we’ve not got a similar feature when it comes to radio buttons…
I’ve created a directive which can be used on radio buttons which mimics this functionality.
The commented source code is here:
I’ve set up a plnkr which demonstrates how to use it and what happens if you don’t use it in the situation I’ve described above.
As always, leave a comment or shout on twitter if you’ve found a better way to accomplish this!comments powered by Disqus