2

I have a table generated with Javascript that output some JSON data. Now I know I should probably not repeat myself so much but one of the element of this array needs to be wrapped in a link, and I don't know how to write a loop that output all members but the also member with some styling. Is there a way to do this in a loop, while keeping the format of output as this code gives? The table head part is already taken care of, the tbody is where I have problem: As you the last element didn't fit in a loop exactly. referring to this problem where I had it in a loop.

for (let j= 0; j< filtered.length; j++){
  var row = table.insertRow(1); 
  row.classList.add("headRow")
  var cell0 = row.insertCell(0);
  cell0.innerHTML = filtered[j].Carat;
  var cell1 = row.insertCell(1);
  cell1.innerHTML = filtered[j].Color;
  var cell2 = row.insertCell(2);
  cell2.innerHTML = filtered[j].Shape;
  var cell3 = row.insertCell(3);
  cell3.innerHTML = filtered[j].Cut;
  var cell4 = row.insertCell(4);
  cell4.innerHTML = filtered[j].Symmetry;
  var cell5 = row.insertCell(5);
  cell5.innerHTML = filtered[j].Report;
  var cell6 = row.insertCell(6);
  cell6.innerHTML = filtered[j].Clarity;
  var cell7 = row.insertCell(7);
  cell7.innerHTML = filtered[j].Polish;
  var cell8 = row.insertCell(8);
  cell8.innerHTML =  '<a href="' + filtered[j].link_view + '"> View</a>' ;
}

2 Answers 2

3

You could try to create a configuration object containing the attribute that will be displayed at each row and a renderer function that will be used to determine how the data is going to be displayed.

Following is a quick example:

var renderer = {
    text: function(data) {
        return data;
    },
    link: function(data) {
        return '<a href="' + data + '">View</a>';
    }
};

var config = [
    {attr: "Carat", renderer: renderer.text},
    {attr: "Color", renderer: renderer.text},
    {attr: "Shape", renderer: renderer.text},
    {attr: "Cut", renderer: renderer.text},
    {attr: "Symmetry", renderer: renderer.text},
    {attr: "Report", renderer: renderer.text},
    {attr: "Clarity", renderer: renderer.text},
    {attr: "Polish", renderer: renderer.text},
    {attr: "link_view", renderer: renderer.link}
];

filtered.forEach(function(data) {

    var row = document.createElement("tr");

    config.forEach(function(entry) {

        var cell = document.createElement("td"),
            value = data[entry.attr];

        cell.innerHTML = entry.renderer(value);

        row.appendChild(cell);

    });

    table.appendChild(row);

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

1 Comment

Worked like a charm, this is amazing I should educate myself about config object. Thank you @Romulo
2

Use an array of Carat, Color property names as strings, and loop over them to extract them from the object and create cells:

const props = ['Carat', 'Color', 'Shape']; // ...
for (let j= 0; j< filtered.length; j++){
  var row = table.insertRow(1);
  row.classList.add("headRow");
  props.forEach((prop) => {
    const cell = row.insertCell();
    cell.innerHTML = filtered[i][prop];
  });
  var cell8 = row.insertCell();
  cell8.innerHTML =  '<a href="' + filtered[j].link_view + '"> View</a>' ;
}

Note that unless the object values are composed of HTML markup, you should use textContent rather than innerHTML. (textContent is both faster and safer)

You don't have to specify an index when calling insertCell because you're inserting the cells in order:

index is the cell index of the new cell. If index is -1 or equal to the number of cells, the cell is appended as the last cell in the row. If index is greater than the number of cells, an IndexSizeError exception will result. If index is omitted it defaults to -1.

If filtered is an array, you can remove the need for ugly manual iteration by using forEach instead, if you wish:

const props = ['Carat', 'Color', 'Shape']; // ...
filtered.forEach((obj) => {
  var row = table.insertRow(1);
  row.classList.add("headRow");
  props.forEach((prop) => {
    const cell = row.insertCell();
    cell.innerHTML = obj[prop];
  });
  var cell8 = row.insertCell();
  cell8.innerHTML =  '<a href="' + obj.link_view + '"> View</a>' ;
});

10 Comments

Thanks but how do add the element cell8 = row.insertCell(8); in a link tag?
Because it's an <a> rather than just text, it won't work in the loop - just add it manually afterwards.
Is the link_view property you're using predictably trustworthy (like from a database or API), or can it come from user input? If from user input, better to insert it by assigning to the href of the <a>, otherwise you'll be permitting arbitrary code execution
doesn't prop already include obj.link_view? this way I get two column of link_view. How I am excluding link_view from forEach?
Just don't put it into the array when defining props - the props array should contain only properties you want to iterate over in the inner loop
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.