<!DOCTYPE html>
<html>

  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js" data-require="angular.js@1.6.0" data-semver="1.6.0"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Radio-Track-By</h1>
    <div ng-app="MyApp">
      <div ng-controller="SLController">
        <!-- Track by... -->
        <p>Track By</p>
        <label ng-repeat="gender in Genders">
          <input type="radio" ng-model="SelectedGender" name="tracked" radio-track-by="Code" ng-value="gender" /> {{gender.Display}}
        </label>
        <br />
        <!-- NON - Track by... -->
        <p>NON - Track By</p>
        <label ng-repeat="gender in Genders">
          <input type="radio" ng-model="SelectedGender" name="nonTracked" ng-value="gender" /> {{gender.Display}}
        </label>
      </div>
    </div>
  </body>

</html>
// Code goes here
var myApp = angular.module("MyApp", []);

myApp.run();

myApp.controller('SLController', function($scope, GenderService){
  $scope.Genders = GenderService.GetGenders();
  // A different object to the one created in the GenderService (below)
  $scope.SelectedGender = {
    Code: "M",
    Display: "Male"
  };
});

myApp.service("GenderService", function() {
  var genders = [{
    Code: "M",
    Display: "Male"
  }, {
    Code: "F",
    Display: "Female"
  },{
    Code: "U",
    Display: "Unknown"
  }];
  
  this.GetGenders = function() {
    return genders;
  };
});

function isDefinedAndNotNull(property) {
    return property !== undefined && property !== null;
};

myApp.directive("radioTrackBy", [function () {
    return {
        restrict: "A",
        scope: {
            ngModel: "=",
            ngValue: "=",
            radioTrackBy: "@"
        },
        link: function (ng, el, attrs) {
            // Set up the watch and reference it so we can remove it when we've got that initial piece of data
            var unWatch = ng.$watch(attrs.ngModel, function (newValue) {
                if (isDefinedAndNotNull(ng.ngModel) && isDefinedAndNotNull(ng.ngModel[ng.radioTrackBy])) {
                    // The model has been populated
                    if (ng.ngValue[ng.radioTrackBy] === ng.ngModel[ng.radioTrackBy]) {
			                  // The track-by property (from the radio's source list) and model property (currently selected radio button) match, set the model object to the matched object
                        ng.ngModel = ng.ngValue;
                    }
		                // We don't want to watch this anymore
                    unWatch();
                }
            });
        }
    };
}]);
/* Styles go here */