I'm having trouble finding a solution that will help me loop through a bunch of elements and putting the chosen values into a table. I've been able to withdraw some values but the method isn't dynamic.
Here is an example:
var Table = {
"credit": {
"link": "site link",
"logoUrl": "logo url",
"message": "message"
},
"groups": [
{
"labels": [
{
"name": "Western Conference",
"type": "conference"
},
{
"name": "Central Division",
"type": "division"
}
],
"standings": [
{
"stats": [
{
"name": "gp",
"value": 20
},
{
"name": "w",
"value": 17
},
{
"name": "l",
"value": 0
},
{
"name": "gf",
"value": 64
},
{
"name": "ga",
"value": 37
},
{
"name": "gd",
"value": 27
},
{
"name": "pts",
"value": 37
}
],
"team": {
"id": 12345,
"link": "team link",
"name": "team name",
"shortName": "team"
}
},
This is the structure of the elements. So far I've used this:
document.getElementById("sGamesPlayed").innerHTML=Table.groups[0].standings[0].stats[0].value;
to withdraw values. However there are more teams, stats and divisions so I would need some kind of loop to go through the elements and put the into a dynamic table.
I would consider you to look at http://underscorejs.org/.
it provides a bunch of utility functions that could help you,
for example, _.each() helps you loop through JSON properties.
for the sample objects you've given (after completing the missing brackets at the end),
_.each(Table.groups[0].standings[0].stats, function(stats){
console.log(stats['name']+","+stats['value'])
})
gives me:
gp,20
w,17
l,0
gf,64
ga,37
gd,27
pts,37
how it works is that you provide the object you want as the first argument and the function that you give as the second argument will be called with each element of the first argument (Assuming it is a list).
I would also urge you to look at underscore templating that you can use to render your table where i put the console.log :
http://net.tutsplus.com/tutorials/javascript-ajax/getting-cozy-with-underscore-js/
http://scriptble.com/2011/01/28/underscore-js-templates/
I guess your question is about filtering the values of the array standings. In order to do that you can use the jQuery grep function (if you want to use jQuery).
For example you can write:
var arr = $.grep(Table.groups[0].standings[0].stats, function(d){return d.value>25})
Which will give
arr = [{"name": "gf","value": 64}, {"name": "ga", "value": 37},{"name": "gd", "value": 27},{"name": "pts", "value": 37}]
If this is not what you meant, can you please create a jsFiddle with a sample of what you want?
Depending on what you want to do with the results, you can go over the object using a scheme like:
var groups, standings, stats, value;
groups = Table.groups;
// Do stuff with groups
for (var i=0, iLen=groups.length; i<iLen; i++) {
standings = groups[i].standings;
// Do stuff with standings
for (var j=0, jLen=standings.length; j<jLen; j++) {
stats = standings[j];
// Do stuff with stats
for (var k=0, kLen=stats.length; k<kLen; k++) {
value = stats[k].value;
// Do stuff with value
}
}
}
Of course I have no idea what the data is for, what the overall structure is or how you want to present it. But if you have deeply nested data, all you can do is dig into it. You might be able to write a recursive function, but it might also become very difficult to maintain if the data structure is complex.
Related
I want to create a JSON API that returns a list of objects. Each object has an id, a name and some other information. API is consumed using JavaScript.
The natural options for my JSON output seems to be:
"myList": [
{
"id": 1,
"name": "object1",
"details": {}
},
{
"id": 2,
"name": "object2",
"details": {}
},
{
"id": 3,
"name": "object3",
"details": {}
},
]
Now let's imagine that I use my API to get all the objects but want to first do something with id2 then something else with id1 and id3.
Then I may be interested to be able to directly get the object for a specific id:
"myList": {
"1": {
"name": "object1",
"details": {}
},
"2": {
"name": "object2",
"details": {}
},
"3": {
"name": "object3",
"details": {}
},
}
This second option may be less natural when somewhere else in the code I want to simply loop through all the elements.
Is there a good practice for these use cases when the API is used for both looping through all elements and sometime using specific elements only (without doing a dedicated call for each element)?
In your example you've changed the ID value from 1 to id1. This would make operating on the data a bit annoying, because you have to add and remove id all the time.
If you didn't do that, and you were relying on the sorted order of the object, you may be in for a surprise, depending on JS engine:
var source = JSON.stringify({z: "first", a: "second", 0: "third"});
var parsed = JSON.parse(source);
console.log(Object.keys(parsed));
// ["0", "z", "a"]
My experience is to work with arrays on the transport layer and index the data (i.e. convert array to map) when required.
For a Chrome app, wich stores data in IndexedDB, i have a object like this:
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"parcels": [
{
"service": "DHL",
"track": "12345"
},
{
"service": "UPS",
"track": "3254231514"
}
]
}
If i store the hole object in an objectStore, can i use an index for "track", which can be contained multiple times in each order object?
Or is it needed or possibly better/faster to split each object into multiple objectStores like know from relational DBs:
order
orderitem
parcel
The solution should also work in a fast way with 100.000 or more objects stored.
Answering my own question: I have made some tests now. It looks like it is not possible to do this with that object in only 1 objectStore.
An other example object which would work:
var myObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"shipping": {"method": "letter",
"company": "Deutsche Post AG" }
}
Creating an index will be done by:
objectStore.createIndex(objectIndexName, objectKeypath, optionalObjectParameters);
With setting objectKeypath it is possible to address a value in the main object like "name":
objectStore.createIndex("name", "name", {unique: false});
It would also be possible to address a value form a subobject of an object like "shipping.method":
objectStore.createIndex("shipping", "shipping.method", {unique: false});
BUT it is not possible to address values like the ones of "track", which are contained in objects, stored in an array. Even something like "parcels[0].track" to get the first value as index does not work.
Anyhow, it would be possible to index all simple elements of an array (but not objects).
So the following more simple structure would allow to create an index entry for each parcelnumber in the array "trackingNumbers":
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"trackingNumbers": ["12345", "3254231514"]
}
when creating the index with multiEntry set to true:
objectStore.createIndex("tracking", "trackingNumbers", {unique: false, multiEntry: true});
Anyhow, the missing of the possibility to index object values in arrays, makes using indexedDB really unneeded complicated. It's a failure in design. This forces the developer to do things like in relational DBs, while lacking all the possibilities of SQL. Really bad :(
I'm trying to join a two tables (versus and words) on multiple ids. I don't really know how to explain it, so I'm just going to show what I mean.
An excerpt from the versus-table:
{
"date": 1427675857789,
"hero": "7b88a237-c288-48f1-bf45-2dcd9f812b54",
"id": "017fe06a-e37d-4f23-92a3-bc52b38de4d7",
"nemesis": "e87a6252-6d08-4c5a-b057-2718e8c07d93",
"points": {
"hero": 58659,
"nemesis": 3021
}
}
Excerpt from the words-table:
{
"id": "7b88a237-c288-48f1-bf45-2dcd9f812b54" ,
"word": "i"
},
{
"id": "e87a6252-6d08-4c5a-b057-2718e8c07d93" ,
"word": "the"
}
I'd like to join the two tables so get something like this:
{
"date": 1427675857789,
"hero": "i",
"nemesis": "the",
"points": {
"hero": 58659,
"nemesis": 3021
}
}
This is what I have so far: r.table("versus").eqJoin("hero", r.table("words")).zip(), which gets me this:
{
"date": 1427675857789 ,
"hero": "7b88a237-c288-48f1-bf45-2dcd9f812b54" ,
"id": "7b88a237-c288-48f1-bf45-2dcd9f812b54" ,
"nemesis": "e87a6252-6d08-4c5a-b057-2718e8c07d93" ,
"points": {
"hero": 60507 ,
"nemesis": 3504
} ,
"word": "i"
}
I'm a little puzzled about how I can join it on the hero-row as well as nemesis-row.
Though I'd be happy with any result that shows most of the things from the versus-table (Doesn't matter if id is there) and two the two words which corresponds to the hero and nemesis id.
EDIT: I've figured something out, but now I'm only able to get the first document, which kind of defeats the purpose of what I'm trying to do... Here's what I got: r.table("versus").eqJoin("hero", r.table("words")).zip().map(r.row.merge({hero: r.row("word")})).eqJoin("nemesis", r.table("words")).zip().map(r.row.merge({nemesis: r.row("word")})).without(["word", "id"])
Well, I did it...finally!
If someone's interested, this is what my new ReQL looks like:
r.table("versus").concatMap(function(v){
return r.table("words").getAll(v("hero"), {index: "id"}).map(function(w){
return r.branch(
v("hero").eq(w("id")),
v.merge({hero: w("word")}),
v
)
})
}).concatMap(function(v){
return r.table("words").getAll(v("nemesis"), {index: "id"}).map(function(w){
return r.branch(
v("nemesis").eq(w("id")),
v.merge({nemesis: w("word")}),
v
)
})
}).without("id")
I want to create a array structure with child entities like this ->
$scope.groups = [
{
"categories": [
{
"name": "PR",
"sortOrder": 0,
"type": "category"
}
],
"name": "DEPT 1",
"sortOrder": 0,
"type": "group",
"id": "-JY_1unVDQ5XKTK87DjN",
"editing": false
}
];
from an array that dosen't have child entities but all the items are listed in one object like this->
$scope.groups = [
{
"name": "PR",
"sortOrder": 0,
"type": "category"
},
{
"name": "AD",
"sortOrder": 3,
"type": "category"
},
{
"name": "DEPT 2",
"sortOrder": 1,
"type": "group",
"id": "-JYZomQKCVseJmaZoIF9",
"editing": false,
"categories": []
},
];
Is there any possible way?
As #Eagle1 has rightly pointed out. You need to define your data model properly to define a function that does that grouping for you. That said, from what I understand you have a $scope.groups array of objects for a specific department containing some categories which you need to consolidate as a child element.
You could start by defining a function that returns an object like you mention:
var organize = function(arr){
cats = [];
dep = {};
$.each( arr, function( i, val ) {
if(val.type == "category")
cats.push(val);
else
dep = val;
});
dep.categories = cats;
return dep;
}
Ultimately, you'll have to traverse the array and look for objects of type category and dump them in an array and have that array as the categories key of the object that you intend to return. I hope it gets you started in the right direction.
of course it is.
It's doable in javascipt although to help you devise something we would need a relationship between categories.
However, that's sounds like something that should be done in your data model (a relationship between dept - category, classic reflexive relationship parent - children). angular should be receiving from the back end an array already ordered.
I need to remove an object from an JSON tree. I know a reference to that object. Is there a nice way to do it via JavaScript or jQuery besides traversing the whole tree?
Example:
party = {
"uuid": "4D326531-3C67-4CD2-95F4-D1708CE6C7A8",
"link": {
"rel": "self",
"href": "http://localhost:8080/cim/party/4D326531-3C67-4CD2-95F4-D1708CE6C7A8"
},
"type": "PERSON",
"name": "John Doe",
"properties": {
"CONTACT": [
{
"category": "CONTACT",
"type": "EMAIL",
"key": "email",
"value": "john.doe#doe.at",
"id": "27DDFF6E-5235-46BF-A349-67BEC92D6DAD"
},
{
"category": "CONTACT",
"type": "PHONE",
"key": "mobile",
"value": "+43 999 999990 3999",
"id": "6FDAA4C6-9340-4F11-9118-F0BC514B0D77"
}
],
"CLIENT_DATA": [
{
"category": "CLIENT_DATA",
"type": "TYPE",
"key": "client_type",
"value": "private",
"id": "65697515-43A0-4D80-AE90-F13F347A6E68"
}
]
},
"links": []
}
And i have a reference: contact = party.properties.contact[1]. And I want to do something like delete contact.
You may delete it this way. I just tested it.
var party = {
// ...
}
alert(party.properties.CONTACT[0]) // object Object
delete party.properties.CONTACT[0] // true
alert(party.properties.CONTACT[0]) // undefined
Fiddle
UPDATE
In the case above party is a direct property of window object
window.hasOwnProperty('party'); // true
and that's why you can't delete a property by reference. Anyhow, behavior of delete operator with host objects is unpredictable. Though, you may create a scope around the party object and then you'll be allowed to delete it.
var _scope = {};
var _scope.party = {
// ...
};
var r = _scope.party.properties.CONTACT[0];
window.hasOwnProperty('party'); // false
alert(r) // object Object
delete r // true
alert(r) // undefined
It only works one way: a variable holds a reference, but there is no way given a particular reference to infer what variables hold it (without iterating over them and comparing).