Home > Back-end >  Handlebars print a table with dynamic array of objects
Handlebars print a table with dynamic array of objects

Time:11-19

i have an array of objects

arr =
[
   {
    user: '[email protected]',
    name: 'b',
    surname: 'b',
    '29_07_2022': 'YES',
    '01_08_2022': 'YES',
    '11_11_2022': 'YES'
  },
   {
    user: '[email protected]',
    name: 'c',
    surname: 'c',
    '29_07_2022': 'YES',
    '01_08_2022': 'NO',
    '11_11_2022': 'NO'
  }
]

all the dates and the values are dynamic

my problem is, i don't know how to access the dates without knowing the name of the index

{{#each arr}} 
          <p> USER {{this.user}}  </p>      Works
          <p> Name {{this.name}}  </p>      Works
          <p> USER {{this.surname}}  </p>      Works
          <p> Date1 {{??????}}  </p>      ?????
    {{/each}} 

my view is something like this

<table style="width:100%">
                      
                        <tr>
                            
                            <th>USER</th>
                            <th>NAME</th>
                            <th>SURNAME</th>
                                    
                           {{#Date}} <th> {{moment Date format="DD/MM/YYYY"}} </th> {{/Date}} 
                           
                        </tr>
                        
                        {{#each arr}} 
                        <tr>
                            
                        
                            <th>{{user}}</th>
                            <th>{{name}}</th>
                            <th>{{surname}} </th>

                        maybe another each here
                            <th>{{???????}}</th>
                        close that each        
                        
                        </tr>
                        {{/each}}     
                        </table>

i want to print a table like this one

  | USER    | NAME | Surname | date 1 | date 2 | date 3 |
  | [email protected] |  b   |    b    |  YES   |   YES  |  YES   |
  | [email protected] |  c   |    c    |  YES   |   NO   |  NO    |

CodePudding user response:

If you can have different keys in some objects

const arr = [
  {
    user: '[email protected]',
    name: 'b',
    surname: 'b',
    '29_07_2022': 'YES',
    '01_08_2022': 'YES',
    '11_11_2022': 'YES'
  },
  {
    user: '[email protected]',
    name: 'c',
    surname: 'c',
    '29_07_2022': 'YES',
    '01_08_2022': 'NO',
    '11_11_2022': 'NO',
    '11_11_2023': 'NO'
  }
]

const keys = [...new Set(arr.flatMap((content) => Object.keys(content)))]

console.log(keys)

I can't test but does something like this works ?

{{#each arr as | user |}}
        {{#each ../keys as | key |}}
             <p> {{key}} {{lookup user key}} </p>
        {{/each}}
{{/each}}

CodePudding user response:

As I see for your comment maybe another each here the objects can have different times.

In that case, you must handle the dates in another array to iterate them and consult inside if the object has that value equal to YES.

Handlebars don't have a method to compare values, so you will need to change your object values to true or false. Another solution is create a Helper as is in the next example:

const handlebars = require("handlebars");
const fs = require("fs");

const arr = [
    {
    user: '[email protected]',
    name: 'b',
    surname: 'b',
    '29_07_2022': 'YES',
    '01_08_2022': 'YES',
    '11_11_2022': 'YES'
    },
    {
    user: '[email protected]',
    name: 'c',
    surname: 'c',
    '29_07_2022': 'YES',
    '01_08_2022': 'NO',
    '11_11_2022': 'NO'
    },
    {
        user: '[email protected]',
        name: 'd',
        surname: 'd',
        '11_11_3000': 'YES'
    }
];

// Handle your dates keys
const dateHeaders = new Set();
// const data = [];
for (const value of arr) {
    // Get only dates of the object
    const dates = new Set(Object.keys(value));
    dates.delete("user");
    dates.delete("name");
    dates.delete("surname");

    // Concat dates
    for (const date of dates) {
        dateHeaders.add(date)
    }
}

// Create an equal condition to use it
// You can ignore it if change the value 'YES' & 'NO' to true & false
handlebars.registerHelper('equal', function (value, value2) {
    return value === value2 ? true : false;
});

// Execute handlebars sending the array and the dateHeaders
const template = handlebars.compile(fs.readFileSync("./template.html", "utf8"));
fs.writeFileSync("./output.html", template({
    arr,
    dateHeaders,
}));

template.html

<table style="width:100%">
    <tr>
        <th>USER</th>
        <th>NAME</th>
        <th>SURNAME</th>
        {{#each dateHeaders}}
        <th>{{this}}</th>
        {{/each}}
    </tr>
    {{#each arr}}
    <tr>
        <th>{{user}}</th>
        <th>{{name}}</th>
        <th>{{surname}}</th>
        {{#each ../dateHeaders}}
        {{#if (equal (lookup ../this this) "YES")}}
        <th>YES</th>
        {{else}}
        <th>NO</th>
        {{/if}}
        {{/each}}
    </tr>
    {{/each}}
</table>

output.html

<table style="width:100%">
    <tr>
        <th>USER</th>
        <th>NAME</th>
        <th>SURNAME</th>
        <th>29_07_2022</th>
        <th>01_08_2022</th>
        <th>11_11_2022</th>
        <th>11_11_3000</th>
    </tr>
    <tr>
        <th>[email protected]</th>
        <th>b</th>
        <th>b</th>
        <th>YES</th>
        <th>YES</th>
        <th>YES</th>
        <th>NO</th>
    </tr>
    <tr>
        <th>[email protected]</th>
        <th>c</th>
        <th>c</th>
        <th>YES</th>
        <th>NO</th>
        <th>NO</th>
        <th>NO</th>
    </tr>
    <tr>
        <th>[email protected]</th>
        <th>d</th>
        <th>d</th>
        <th>NO</th>
        <th>NO</th>
        <th>NO</th>
        <th>YES</th>
    </tr>
</table>

NOTE: If you want the dates in an specific order (actually is FIFO) you must convert dateHeaders to an Array and apply a sort.

  • Related