I was able to resolve the "$ref" links in my json code by adapting the code, this blogger posted, to be Angular compliant.
http://willseitz-code.blogspot.com/2013/01/javascript-to-deserialize-json-that.html
I created an angular service to resolve the "$ref" I get from NewtonSofts JSON serializer.
// http://willseitz-code.blogspot.com/2013/01/javascript-to-deserialize-json-that.html
(function () {
'use strict';
angular
.module('app')
.factory('jsonPointerParseService', jsonPointerParseService);
jsonPointerParseService.$inject = [];
function jsonPointerParseService() {
var hashOfObjects = {};
var service = {
pointerParse: pointerParse
};
return service;
function collectIds(obj) {
if (jQuery.type(obj) === "object") {
if (obj.hasOwnProperty("$id")) {
hashOfObjects[obj.$id] = obj;
}
for (var prop in obj) {
collectIds(obj[prop]);
}
} else if (jQuery.type(obj) === "array") {
obj.forEach(function (element) {
collectIds(element);
});
}
}
function setReferences(obj) {
if (jQuery.type(obj) === "object") {
for (var prop in obj) {
if (jQuery.type(obj[prop]) === "object" &&
obj[prop].hasOwnProperty("$ref")) {
obj[prop] = hashOfObjects[obj[prop]["$ref"]];
} else {
setReferences(obj[prop]);
}
}
} else if (jQuery.type(obj) === "array") {
obj.forEach(function (element, index, array) {
if (jQuery.type(element) === "object" &&
element.hasOwnProperty("$ref")) {
array[index] = hashOfObjects[element["$ref"]];
} else {
setReferences(element);
}
});
}
}
// Set the max depth of your object graph because JSON.stringify will not be able to
// serialize a large object graph back to
function setMaxDepth(obj, depth) {
// If this is not an object or array just return there is no need to
// set its max depth.
if (jQuery.type(obj) !== "array" && jQuery.type(obj) !== "object") {
return obj;
}
var newObj = {};
// If this object was an array we want to return the same type in order
// to keep this variable's consistency.
if (jQuery.type(obj) === "array") {
newObj = [];
}
// For each object or array cut off its tree at the depth value by
// recursively diving into the tree.
angular.forEach(obj, function (value, key) {
if (depth == 1) {
newObj = null;
}
else if (jQuery.type(value) === "array") {
if (setMaxDepth(value, depth - 1)) {
newObj[key] = setMaxDepth(value, depth - 1)
} else {
newObj = [];
}
} else if (jQuery.type(value) === "object") {
if (setMaxDepth(value, depth - 1)) {
newObj[key] = setMaxDepth(value, depth - 1)
} else {
newObj = [];
}
} else {
newObj[key] = value;
}
}, newObj);
return newObj;
}
function pointerParse(obj, depth) {
var newObj = obj;
hashOfObjects = {};
collectIds(newObj);
setReferences(newObj);
if (depth) {
newObj = setMaxDepth(newObj, depth);
}
return newObj;
}
}
})();
Usage would be like so:
var newObj = jsonPointerParseService.pointerParse(obj);
Please keep in mind, this is an Angular service. So I inject it into whichever controller needs to have these references resolved, and make the call to pointerParse() accordingly.
Please note though that if you want to post this object back to the server, your browsers JSON.stringify() call has to be able to handle an object with circular references. By default, in my case, Angular does not call JSON.stringify() with the parameters required to be able to stringify an object with circular references. So, in this case I would suggest posting only a small portion of data and not this entire object back or instantiating your own call to stringify an object like this.
Lastly, I must say that dealing with $ref is a pain and I decided to preserve reference handling with only arrays. This seemed to work well for me. I still had to access array values with $values however I didnt have to worry about resolving references and didnt have to worry about the server blowing up trying to serialize all of the object circular references to json.
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Arrays;
Update: Even with only resolving arrays there are still references that you may need to resolve. In those instances use the pointerParse() function to take care of them.