How to access nested objects in json by angularjs $resource - json

I have .NET WCF service providing REST service. Everything works for me, until I am trying to send object with nested objects. Then I am getting nothing in angularjs. How can I use/access nested object for data exchange?
.NET service part:
[OperationContract] // route prefix 'api'
[WebGet(UriTemplate = "users/{id}/privileges", ResponseFormat = WebMessageFormat.Json)]
public PrivilegeSet GetPrivileges(string id)
{
var response = new PrivilegeSet();
List<Role> roles = new List<Role>();
roles.Add(new Role() { RoleId = 1, Name = "Role 1", Active = true });
roles.Add(new Role() { RoleId = 2, Name = "Role 2", Active = true });
roles.Add(new Role() { RoleId = 3, Name = "Role 3", Active = false });
response.Roles = roles;
List<SubRole> subRoles = new List<SubRole>();
subRoles.Add(new SubRole() { SubRoleId = 1, Name = "SubRole 1", RoleId = 1, Active = true });
subRoles.Add(new SubRole() { SubRoleId = 2, Name = "SubRole 2", RoleId = 1, Active = true });
subRoles.Add(new SubRole() { SubRoleId = 3, Name = "SubRole 3", RoleId = 1, Active = false });
response.SubRoles = subRoles;
return response;
}
JSON structure:
{
"Roles": [
{
"Active": true,
"Name": "Role 1",
"RoleId": 1
},
{
"Active": true,
"Name": "Role 2",
"RoleId": 2
},
{
"Active": false,
"Name": "Role 3",
"RoleId": 3
}
],
"SubRoles": [
{
"Active": true,
"Name": "SubRole 1",
"RoleId": 1,
"SubRoleId": 1
},
{
"Active": true,
"Name": "SubRole 2",
"RoleId": 1,
"SubRoleId": 2
},
{
"Active": false,
"Name": "SubRole 3",
"RoleId": 1,
"SubRoleId": 3
}
]
}
Angularjs service:
angular.module('privilegeService', ['ngResource']).
factory('Privilege', function ($resource) {
return $resource('api/users/:userId/privileges', {userId: '#id'});
});
Angularjs fetching part:
function PrivilegesCtrl($scope, Privilege) {
$scope.privileges = Privilege.query({userId:2}); // privileges remains empty using nested objects, with one level object works fine
...
Why privileges remains empty when JSON has nested objects? And how to access nested objects in the view?

When you use the $resource service the .query action assumes your response is an array. You can specify that the response is not an array when using .query by specifying it when creating the resource with the third parameter below:
angular.module('privilegeService', ['ngResource']).
factory('Privilege', function ($resource) {
return $resource('api/users/:userId/privileges',
{userId: '#id'},
{'query': {method:'GET', isArray:false}});
});
Check out this plnkr for an example. If you take out the {'query': {method:'GET', isArray:false}} your response will be an empty array.
Note 1: your console is likely showing an error TypeError: Object #<Resource> has no method 'push' which, when working with .query, usually means an array is expected from your REST call.
Note 2: the resource action defaults are described in the $resource documentation as follows:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };

Related

Getting inventory contexts of Steam users

A stack overflow answer explains how to retrieve a user's public inventory
http://steamcommunity.com/profiles/<PROFILEID>/inventory/json/<APPID>/<CONTEXTID>
I read that context ID must be set as 2 to find items for most games, but this is not always the case. Is there any official API to find a user's inventory contexts? steamapis.com already has a paid API which performs this task:
{
"steamID": {
"universe": 1,
"type": 1,
"instance": 1,
"accountid": 78261062
},
"name": "PEPZ",
"onlineState": "online",
"stateMessage": "Online",
"privacyState": "public",
"visibilityState": "3",
"avatarHash": "5b702b331ddeb928225ad562a3e729aecd191b9a",
"vacBanned": false,
"tradeBanState": "None",
"isLimitedAccount": false,
"customURL": "pepzwee",
"memberSince": "2011-02-21T22:00:00.000Z",
"location": "Estonia",
"realName": "SteamApis.com Developer",
"summary": "",
"groups": [
{
"universe": 1,
"type": 7,
"instance": 0,
"accountid": 28077004
},
...
],
"primaryGroup": {
"universe": 1,
"type": 7,
"instance": 0,
"accountid": 28077004
},
"contexts": {
"440": {
"appid": 440,
"name": "Team Fortress 2",
"icon": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/440/e3f595a92552da3d664ad00277fad2107345f743.jpg",
"link": "http://steamcommunity.com/app/440",
"asset_count": 11,
"inventory_logo": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/440/e613d1d46de26ea755105b898cc8830d305353f3.png",
"trade_permissions": "FULL",
"load_failed": 0,
"rgContexts": {
"2": {
"asset_count": 11,
"id": "2",
"name": "Backpack"
}
}
},
...
}
}
Where "rgContexts" contains inventory context for each game.
I found out with some inspect element work, that there is a script tag available with the exact information you need. This is an example of my profile:
var g_rgWalletInfo = {"success":false};
var g_bInventoryIsInModalDialog = false;
var g_bIsInMarketplace = false;
UserYou.SetSteamId( '76561199033382814' );
var g_rgAppContextData = {"753":{"appid":753,"name":"Steam","icon":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/753\/135dc1ac1cd9763dfc8ad52f4e880d2ac058a36c.jpg","link":"https:\/\/steamcommunity.com\/app\/753","asset_count":303,"inventory_logo":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/753\/db8ca9e130b7b37685ab2229bf5a288aefc3f0fa.png","trade_permissions":"FULL","load_failed":0,"store_vetted":"1","rgContexts":{"6":{"asset_count":303,"id":"6","name":"Community"}}},"730":{"appid":730,"name":"Counter-Strike: Global Offensive","icon":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/730\/69f7ebe2735c366c65c0b33dae00e12dc40edbe4.jpg","link":"https:\/\/steamcommunity.com\/app\/730","asset_count":61,"inventory_logo":"https:\/\/cdn.cloudflare.steamstatic.com\/steamcommunity\/public\/images\/apps\/730\/3ab6e87a04994b900881f694284a75150e640536.png","trade_permissions":"FULL","load_failed":0,"store_vetted":"1","rgContexts":{"2":{"asset_count":61,"id":"2","name":"Backpack"}}}};
var g_strInventoryLoadURL = 'https://steamcommunity.com/id/stoplookingatmyid/inventory/json/';
$J( function() {
UserYou.LoadContexts( g_rgAppContextData );
} );
$J( function() {
var bHasPendingGifts = false;
InitInventoryPage( bHasPendingGifts, -1, false );
});
var g_bInClient = false;
var g_bInChinaRealm = false;
var g_bViewingOwnProfile = false;
var g_bMarketAllowed = false;
var g_strLanguage = 'english';
var g_strCountryCode = "US";
var g_strProfileURL = 'https://steamcommunity.com/id/stoplookingatmyid';
Some of this data is junk, but g_rgAppContextData is exactly what you need in JSON format, and it just needs to be parsed if your programming language of choice. In this example, 753 is the app id of Steam, with 6 being the context id, and 730 is CSGO'S app id, with 2 as the context id. with This data won't be present if the user has a private steam inventory.

How to remove Task json properties in Nancy.Response.AsJson

I've made one of my API endpoints and inner logic asynchronous and when previously I've used Response.AsJson(Foo.bar()) , it would return the json representation normally, but now I see this appended to it:
{
"result": [
{
"id": "59d680cc734d1d08b4e6c89c",
"properties": {
"name": "value"
}
}
],
"id": 3,
"exception": null,
"status": 5,
"isCanceled": false,
"isCompleted": true,
"isCompletedSuccessfully": true,
"creationOptions": 0,
"asyncState": null,
"isFaulted": false
}
But I want it to be like this:
"id": "59d680cc734d1d08b4e6c89c",
"properties": {
"name": "value"
}
As I understand, it's because I've wrapped my object in a Task , but I can't figure out, how with Nancy framework, which I use the Response.AsJson, to make it so the properties are excluded. I can obviously omit the Response.AsJson of the returned object, but then response is no longer Json if requesting through web-browser for example.
For further example
NancyModule for routing API:
public ItemCatalogModule(IItemCatalog itemCatalog) : base("/itemCatalog")
{
Get("/fetch/{id}", async parameters =>
{
var id = (string) parameters.id;
var response = await Response.AsJson(itemCatalog.GetItem(id));
return response;
});
}
How the interface looks like of ItemCatalog:
public interface IItemCatalog
{
Task<Item> GetItem(string id);
}
You shoud do this :
public ItemCatalogModule(IItemCatalog itemCatalog) : base("/itemCatalog")
{
Get("/fetch/{id}", async parameters =>
{
var id = (string) parameters.id;
return Response.AsJson(await itemCatalog.GetItem(id));
});
}

Access nested JSON object in AngularJS controller

I am new to AngularJS and trying to create a $scope for tracks for later usage
data.json (sample):
[
{
"album": "Album name",
"tracks": [
{
"id": "1",
"title": "songtitle1",
"lyric": "lyrics1"
},
{
"id": "2",
"title": "songtitle2",
"lyric": "lyrics2"
}
]
}
]
Controller
app.controller('lyricsCtrl', function($scope, $http) {
$http.get('data.json')
.then(function(result) {
$scope.albums = result.data;
$scope.tracks = result.data.tracks;
console.log($scope.tracks); //Undefined...
});
});
Why is $scope.tracks undefined?
If your json file is as is:
[
{
"album": "Album name",
"tracks": [
{
"id": "1",
"title": "songtitle1",
"lyric": "lyrics1"
},
{
"id": "2",
"title": "songtitle2",
"lyric": "lyrics2"
}
]
}
]
We have a response of:
data: Array[1]
0: Object
album: "Album name"
tracks: Array[2]
Since data is returned as an array you would handle like any other javascript array and access by index, so you could do a loop or if you know only 1 result is going to be returned you could use the zero index:
$http.get('data.json').then(function(result) {
console.log(result);
// Assign variables
$scope.album = result.data[0].album;
$scope.tracks = result.data[0].tracks;
for (var i = 0, l = $scope.tracks.length; i < l; i++) {
console.log($scope.tracks[i].title);
}
});
result.data is an array,So you must have to use index to access its child like:-
$scope.tracks = result.data[0].tracks;
It should be result.data[0].tracks as data is an array
$scope.tracks = result.data[0].tracks;

Json response + Node.js

In my node app i pass bunch of queries as Object.I have to form as exact format of request.
Consider my request as:
{q0:{query0},q1:{query1},q2:{query1}}
My reponse should be {q0:{response0},q1{response1},q2{response2}
My actual query(In my app):
{"q0":{"query":"James Madison","type":"/people/presidents","type_strict":"should"},
"q1":{"query":"George Washington","type":"/people/presidents","type_strict":"should"},
"q2":{"query":"John Adams","type":"/people/presidents","type_strict":"should"},
"q3":{"query":"James Monroe","type":"/people/presidents","type_strict":"should"},
"q4":{"query":"Thomas Jefferson","type":"/people/presidents","type_strict":"should"}}
But my response is coming as:
{"result":[q0result,q1result,q3result]}
My code:
for (var id in presidents ) {
var match
if (query == presidents[id]) {
//console.log(" Inside match")
match = true;
}
else {
match = false;
}
matches.push({
"id": id,
//"name": name,
"score": 100,
"match": match,
"type": [{
"id": "/people/presidents",
"name": "US President"
}]
})
}
callback(matches);
json = JSON.stringify({"result":matches});
res.writeHead(200, {'content-type':'application/json'});
res.end(json);
Please help me to solve this..Thanks in advance.
You are pushing the result in an array instead you should create a property in the result object as below
var matches = {};
for (var id in presidents ) {
if (query == presidents[id]) {
//console.log(" Inside match")
match = true;
}
else {
match = false;
}
matches[id] ={
"id": id,
//"name": name,
"score": 100,
"match": match,
"type": [{
"id": "/people/presidents",
"name": "US President"
}]
};
}
callback(matches);

Passing Json from action to view by ViewBag

I'm trying to get the result below using JsonResult, but I can't
var localJSON = [
{ "id": "1", "label": "tagName1", "value": "tagValue1" },
{ "id": "2", "label": "tagName2", "value": "tagValue2" },
{ "id": "3", "label": "tagName3", "value": "tagValue3" },
{ "id": "1553", "label": "tagName1553", "value": "tagValue1553" }
];
Here is the way I use:
controller
private JsonResult GetAvailableTags()
{
var tagsList = Facade.Tags.Get(CurrentLocale.ID);
var retValue = new
{
id = tagsList.Select(x => x.ID).ToArray(),
label = tagsList.Select(x => x.Name).ToArray(),
value = tagsList.Select(x => x.Name).ToArray()
};
return Json(retValue);
}
public ActionResult AddPhoto()
{
var availblableTags = GetAvailableTags();
JavaScriptSerializer serializer = new JavaScriptSerializer();
ViewBag.AvailableTags = serializer.Serialize(availblableTags.Data);
return View();
}
view
var localJSON = [ #Html.Raw(ViewBag.AvailableTags)];
The result is
var localJSON = [
{"id":[1,2,3,1553],"label":["tagName1","tagName2","tagName3","tagName1553" ],"value":["tagName1","tagName2","tagName3","tagName1553" ]}
];
What should I do to resolve that?
I assume you want to get x.Value for value in JSON? Then change your assignment for retValue to
var retValue = tagsList.Select(
x => new
{
id = x.Id,
label = x.Name,
value = x.Value
}).ToArray();
In your retValue assignment code you were creating a single object of anonymous type with array-typed members id, label and value. For the output you want you need to create an array, each member of which is an object with simple fields id, name and value.