0

I have a JSON file that looks like this https://pastebin.com/ushcMpwY, and I would like to load it into a HTML table that has 6 columns (group, name, registration 1, registration 2, week, half term). Here is an example of what I would like it to produce:

<table id="people">
    <tr>
        <th>Group name</th>
        <th>Name</th>
        <th>Registration 1</th>
        <th>Registration 2</th>
        <th>Week</th>
        <th>Half term</th>
    </tr>

    <!-- Where JS inserted HTML begins -->
    <tr class="9" id="HA09_000">
        <td>9</td>
        <td>Wyatt Fedlt</td>
        <td>R</td>
        <td>R</td>
        <td>0</td>
        <td>1</td>
    </tr>

    ...

    <!-- Where JS inserted HTML ends -->

</table>

It was suggested to me that I should use an OOP approach such as this one https://pastebin.com/0TRrLT6n, and while I was able to get that to work with regards to printing out the data, it didn't seem like an approach that would be very useful for making the actual table. At the moment it is very buggy. It produces a table that looks like this: http://prntscr.com/m9eh44 and I just don't know how to get it to make one like I've described above, and so I'd rather go back to a procedural approach that I understand like the one I have referenced in the Pseudo Code below.

Initially, I tried to write some code what would work like this Pseudo Code:

TABLE = GET_TABLE_BY_ID('people')
PERSON_COUNT = 0
FOR GROUP IN DATA:
    FOR PERSON IN GROUP:
        ROW = TABLE.INSERTROW(PERSON_COUNT)
        ROW.CLASSLIST.ADD(GROUP.NAME)
        ROW.ID.ADD(PERSON.ID)
        CELL = ROW.INSERTCELL(0)
        CELL.INNERHTML = GROUP.NAME
        INFO_COUNT = 0
        FOR INFO IN PERSON:
            CELL = ROW.INSERTCELL(INFO_COUNT)
            CELL.INNERHTML = INFO
            INFO_COUNT++
        PERSON_COUNT++

That resulted in some actual code like this (at that point I was just trying to print out the values since it would then be simple enough to convert it into code to generate the table).

$.getJSON("http://localhost:8000/data.json", function(data) {
    output_json(data);
});

function output_json(data) {
    var i, j, k;
    for (i = 0; i < Object.keys(data).length; i++) {
        group_ = Object.values(data)[i];
        for (j = 0; j < Object.keys(group_).length; j++) {
            person = Object.values(group_)[j];
            person_id = Object.keys(person)[0];
            console.log(Object.keys(data)[i]); // Group
            console.log(person_id); // ID
            for (k = 0; k < Object.keys(person).length; k++) {
                person_info = Object.values(person)[k][0];
                console.log(person_info); // Information
            }
        }
    }
}

I was hoping for this code to print out the data that I would like to input into the table for each person, i.e. their group, their name, etc. I wanted it to do this:

9

HA09_000

Wyatt Feldt

R

R

0

1

However, my code currently produces this:

9

HA09_000

{name: "Wyatt Feldt", registration_1: "R", registration_2: "R", week: 0, half_term: 1}

If someone could show me how to at least print the values then (as long as it is procedural), I'm confident I can add the table part in myself. However, if you think this really should be OOP then I would hugely appreciate it if you could explain to me how I could implement the table part as well. I know I can make this work with 4 for loops, but that's very inefficient and I'm confident it can be done in 3 much clearer loops like I've laid out in my Pseudo Code.

Thanks.

2
  • What do you get if you console.log(person_info.half_term); Can you use that to make the table? Commented Jan 19, 2019 at 19:48
  • @MatthewPage That would work, but it would mean I'd have a LOT of code duplication. I'm just trying to do it like my Pseudo Code really. Commented Jan 19, 2019 at 19:49

2 Answers 2

1

IMO a more readable/elegant solution is to separate concerns a little and use pure functions...

  1. Flatten all your data
  2. Build HTML table rows
  3. Add to table
    let rowKeys = Object.keys(data);

    // iterate over the 'first level' keys with the goal of extracting the values needed in the final objects (elemClass), while then extracting the 'second level' object (group) so that you can access its data.
    let rowsFlattened = rowKeys.reduce((acc,key) => {
            let elemClass = key,
                group = data[key];

             let people = group.reduce((acc2,groupObj)=> {
                    let elemId = Object.keys(groupObj)[0],
                        person = groupObj[elemId][0];

                        return [
                            ...acc2,
                            {
                                ...person,
                                className: elemClass,
                                id: elemId
                            }
                        ]
                },[])

                // these 'spread operators' merge either objects or arrays, in this case an array.
                return [
                    ...acc,
                    ...people
                ]

        // this '[]' is the starting accumulator, which you have access to in the 'acc' parameter above. After each iteration this 'acc' value is replaced by whatever value is returned in the previous iteration. 
        },[]);

    // 
    let rowsHTML = rowsFlattened.map(obj => {
            let { className, id, name, registration_1, registration_2, week, half_term} = obj;
            return `
                <tr class="${className}" id="${id}">
                    <td>${className}</td>
                    <td>${name}</td>
                    <td>${registration_1}</td>
                    <td>${registration_2}</td>
                    <td>${week}</td>
                    <td>${half_term}</td>
                </tr>
            `
        })  

        $('#people').html(rowsHTML);

My solution is a little long so please see the below jsFiddle...

https://jsfiddle.net/u1ekga7y/

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you for your help, but I really have no idea what's going on in your code. I'm not proficient in anything JavaScript specific and I can't quite work out what's happening. For example, if I wanted to add the group like I described, I wouldn't have a clue how to do so. Is there any chance you could help me make it work like in my Pseudo Code? I honestly think that would be way more readable and make more sense. Sorry!
Okay well I worked out how to add the group with just <td>${className}</td>, but I still can't follow most of the code and I don't really want to just copy code I don't understand. Also, this is jQuery right?
Certainly happy to help. The best way yo do so will be to look at the HTML produced from the JSFiddle link I provided and let me know if there are inconsistencies from what you're trying to achieve.
Sorry, I don't think I was very clear. Your code does exactly what I want it to do (after I added <td>${className}</td> so it also shows the group). My problem is that I'm pretty new to JS since I mostly code in Python, and so I don't understand a lot of what's happening. I was hoping to get it done in a method similar to my Pseudo Code as I understand how that works. Like I said, I don't like to just copy code if I don't know what's happening.
90% of that is just JS, but it is ES6 (the most recent version) so there are some newer language features like Object Spread Operators (...somVariable). This basically extracts all of the property and values from an object and merges them into a new object
|
0

I'm guessing you want the person info to be in an array? Add another loop to go through the person_info object keys and values..

        for (k = 0; k < Object.keys(person).length; k++) {
            person_info = Object.values(person)[k][0];
            console.log(person_info); // Information
        }

To

        var person_info_data = [];
        for (k = 0; k < Object.keys(person).length; k++) {
            person_info = Object.values(person)[k][0];
            for (l = 0; l < Object.keys(person_info).length; l++) {
                person_info_data.push(Object.values(person_info)[l])
            }
            console.log(person_info_data); // Information
        }

1 Comment

Thanks for the suggestion, but this is the solution I was talking about in my question that I don't like. It has a totally unnecessary for loop and isn't very readable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.