0

I have long JSON data, where the object is kinda long with some numbering on it. What should i do is make that JSON to table with the Head is the number of each object.

This is the snapshot of what i do (with the JSON Data)

jsfiddle And the looping i do is making thead and tbody like this

$.each(Object.keys(myObj.data[0]), function(_, key) {

  tr.append("<th>" + key + "</th>");

});
tr.appendTo(thead);

$.each(myObj.data, function(_, obj) {
  tr = $("<tr />");
  $.each(obj, function(_, text) {

    if (!text.namashift) {
      tr.append("<td>" + text + "</td>")
    } else {
      tr.append("<td>" + text.namashift + "</td>")
    }

  });
  tr.appendTo(tbody);
});

This is the one i grasp and want, but there's few problem i can't do:

  1. Sorting the JSON, what i want is "id" "nama" "bulan" "tahun" thead on the first column, it's because JSON is unordered ? althought on the JSON list that objects is on the front, when becoming table it's go to the back.
  2. Make condition only object "nama" and all the number object appear on the table (1-31)
  3. What if some of JSON object array not having same number (ex. one array is 1-30, and other is 1-31. Then the 1-30 td is blank on the last column)

It's my first time handle something like this, and i want to understand more about JSON in the future. It's kinda different with array list... meanwhile i want the most efficient way to do this. I hope someone can give me Light to this, thank you so much.

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
dooooooofai
  • 88
  • 1
  • 15
  • 1. https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order *the iteration order is a combination of the insertion order for strings keys, and ascending order for number-like keys* - following the links, gives a page that details that numeric keys are always first, followed by alpha keys in the order they were added. – freedomn-m Mar 01 '21 at 14:12
  • 2. You'll need to either hardcode how the table is rendered or exclude alpha (non-numeric keys) except "nama". – freedomn-m Mar 01 '21 at 14:13
  • 3. Again, either hardcode how it's rendered or parse all of the data first - eg to find the max number (or specific numbers) to show by adding them to an array/list first then loop that array rather than the data[i]'s properties. – freedomn-m Mar 01 '21 at 14:14
  • 1/2/3. You could add a `header` record to your json that describes how to build the table – freedomn-m Mar 01 '21 at 14:15
  • then should i change the JSON to array list first ? what 'hardcode' do you suggest? i kinda don't know where should i start.. – dooooooofai Mar 01 '21 at 14:15
  • "hardcode" would be like `for (var i=0; i<30; ++i)` - ie define the table in the code rather than data-driven. *probably* not what you want – freedomn-m Mar 01 '21 at 14:16
  • Sorry for asking this, but can i have more raw code from the loop until it rendering(not detailed one, just one showing one column?) what you mean is making variable to arrange the table ... right? sorry if i'm asking question like this... – dooooooofai Mar 01 '21 at 14:20
  • No worries - will take a few minutes – freedomn-m Mar 01 '21 at 14:21
  • thank you so much sir (waiting like obedient student) – dooooooofai Mar 01 '21 at 14:32

1 Answers1

1

Your first option would be provide a fixed table, but as you've started down the data-driven route, let's rule that out.

A fixed table would be where the table is pre-defined in the HTML and then you add data to it.

A hardcoded table would be where assumptions are made about the data, such as it having 31 columns. So you can write your loop as a basic for loop:

for (var i=0;i<=31;i++) {  
    tr.append("<th>" + i + "</th>");    

In both the above cases, if your data changes (eg add a column 31) then you'd need to update the HTML. Which is why we write data-driven applications (assuming we can trust the data source...)

Sorting the JSON [columns] - "id" "nama" "bulan" "tahun" thead as the first columns

This answer provides details here. In summary, "numeric" keys are displayed first and then your alphabetical keys.

To get them in the order you want, you could change your data so it's not numeric, eg from

[ { "2": { "shift": "9" ...

to

[ { "key2": { "shift": "9" ...

then ensure your other columns are at the front and tweak your code to exclude the prefix.

Assuming you don't want to change your keys, you can change your thead loop so that it finds alpha keys first (two loops), eg:

let tr = $("<tr />");
$.each(Object.keys(myObj.data[0]), function(_, key) {
  if (parseInt(key)) return;
  tr.append("<th>" + key + "</th>");
});
$.each(Object.keys(myObj.data[0]), function(_, key) {
  if (!parseInt(key)) return;
  tr.append("<th>" + key + "</th>");
});
tr.appendTo(thead);

Bit of DRY here, but as long as the tr.append isn't too long, no-one should complain.

You'll also need to change the tbody loop to get them in the correct order

However, when combined with the next requirement, there's no need for the above as there's only one non-numeric header

Make condition only object "nama" and all the number object appear on the table (1-31).

In this case, add the nama column first, then the numeric columns, using the same condition as above, eg:

let tr = $("<tr />");
tr.append("<th>nama</th>");
$.each(Object.keys(myObj.data[0]), function(_, key) {
  if (!parseInt(key)) return;
  tr.append("<th>" + key + "</th>");
});
tr.appendTo(thead); 

Again, this will need changes to the data loop - which we can make easier below.

What if some of JSON object array not having same number (ex. one array is 1-30, and other is 1-31. Then the 1-30 td is blank on the last column)

In this case you should parse the list first to find all the keys you're interested in, then create the same keys on each tr.

In the simple form where data[0] contains all the required headers, it would be:

let cols = [];
cols.push("nama");
$.each(Object.keys(myObj.data[0]), function(_, key) {
  if (!parseInt(key)) return;
  cols.push(key);
});  

but we wants to get other columns as well - in your fiddle, I've removed "1" from the first data and added "33" to 2nd data to show these working (missing 32 so it's not in the columns)

let cols = []; $.each(myObj.data, (, data) => { $.each(Object.keys(data), function(, key) { if (!parseInt(key)) return; if (!cols.includes(key)) cols.push(key); }); }); // sort here using a numeric sort cols = cols.sort(function(a, b) { return a - b; }); // add specific columns at the front cols.unshift("nama");

They need to be sorted to get the initially-missing "1" back to the start.

Alternatively you could get a min-max values here are render all between, which would also output the "32".

Then add to the table, by looping the cols, not the data keys

let tr = $("<tr />");
$.each(cols, (_,key) => tr.append("<th>" + key + "</th>") );
tr.appendTo(thead);

$.each(myObj.data, function(_, obj) {
  tr = $("<tr />");
  $.each(cols, (_,key) => {
     tr.append("<td>" 
               + (!obj[key] 
                     ? "" 
                     : (obj[key].namashift 
                          ? obj[key].namashift 
                          : obj[key])) 
               + "</td>") 
  });
  tr.appendTo(tbody);
});

Where !obj[key] ? "" checks for missing values and obj[key].namashift ? is your original check for numeric key with namashift vs namashift itself. You can expand this to if / else for your own clarity.

Updated fiddle: https://jsfiddle.net/rz26xabm/

Alternatively, if you can change the JSON, then add a "header" row to describe how to build the table and loop on that.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • [let me insert pikachu gasp face here] Let me Thank you first sir, that really detailed explanation and i can easily review and understand it. Yes, i also feels it will become easier if the JSON format changed, but unfortunately i'm not the one making the JSON output. cont. – dooooooofai Mar 01 '21 at 15:05
  • i think i can grasp the logic. but then i can't change the th of this table right? because it's based of the object data.... (like change "nama" to any word) but it's basically what i need. Again, thank you so much. – dooooooofai Mar 01 '21 at 15:09
  • Sir sorry, i have problem about giving condition inside the making of tbody content (https://jsfiddle.net/dbrn9wm2/1/) giving 'aa' when the namashift content is LIBUR, but then there's error Cannot read property 'namashift' of undefined, why the namashift not defined here? – dooooooofai Mar 01 '21 at 15:52
  • 1
    You need to check for `!obj[key]` *first* - this is the check for missing values, eg checking for col `[33]` when there's only 31 cols. It's `undefined` as it's missing for that column. Add `if (!obj[key]) return;` as the first line in the loop. https://jsfiddle.net/vo7pe0cy/ – freedomn-m Mar 01 '21 at 15:59