4

I'm trying to create a table from a JSON response formulated from a submitted form, therefore the initial render needs to be blank, but this blank state is proving to be an issue.

The issue is complicated further by the fact that the response could have different headers, number of columns, and order.

Parent component

This gets the resultData and passes it to a child component

<ReportsTable title={this.props.title} resultData={this.state.resultData} /> 

Child component

var ReportsTable = React.createClass({
    render: function() {
        var resultData = this.props.resultData;

        return(
                <div>
                    <h3>{this.props.title}</h3>
                    <table>
                        <tr>
                            //iteration here
                        </tr>
                    </table>
                </div>
        )

    }
});

Any attempt at iteration gives me a

Uncaught TypeError: Cannot read property XXX of undefined


The Data received is in this type of format

[Array[1], Array[1]]
    0: Array[1]
        0: Object
            family_name: "Sales"
            gross_margin: "0%"
            net_profit: "$0.00"
            profit_percent: "0%"
            quantity_on_hand: 2863
            retail: "$9,347.12"
            total_cost: "$7,615.96"
            total_sold: 49 
    1: Array[1]
        0: Object
            family_name: "Service"
            gross_margin: "0%"
            net_profit: "$0.00"
            profit_percent: "0%"
            quantity_on_hand: 147.5
            retail: "$939.05"
            total_cost: "$268.40"
            total_sold: 10.8

[UPDATE]

So we modified the response from the server so that I get one less nest in the Array. But now when I try resultData.map(function(item) { }) and I get an "Uncaught TypeError: undefined is not a function" error as I'm trying to map through the properties of the Object. When I try to map through an Array it works so I don't think it's my syntax.

In the end, my trouble is iterating through the properties of each Object.

This part from the parent works

{resultData.map(function(tableRow, i) {
    return (
        <TableRow tableRow={tableRow} key={i} />
    );
})}

This part in the Child Component does not

var TableRow = React.createClass({
    render: function(){
        var tableRow = this.props.tableRow;
        console.log(tableRow);

        return(
                <tr key={tableRow}>
                    {tableRow.map(function(tableItem, i){
                        <td key={i}>{tableItem}</td>
                    })}
                </tr>
        );
    }
});
Dmitry Shvedov
  • 3,169
  • 4
  • 39
  • 51
johncho
  • 641
  • 2
  • 11
  • 25
  • Can you post what the actual data looks like? And the call that receives this datsa? – tymeJV Mar 12 '15 at 19:49
  • Sure, just added a typical response. I can display the response without any formatting just fine, it's the formatting that's troubling me. – johncho Mar 12 '15 at 19:56
  • 1
    So, `resultData.map(function(item) { })` throws an error? – tymeJV Mar 12 '15 at 19:58
  • 1
    Trying it now, and tomorrow morning. It's giving me the top layer, and not exactly what I need, but I think I can nest these to get to what I need. Thank you. I'll write back when I have an answer. – johncho Mar 12 '15 at 20:26
  • 1
    You have doubly-nested arrays, so your iteration is probably wrong. That is the crux of your question and issue, so I'm confused why you didn't post the iteration code. Update the question, and it will probably be obvious what the issue is. – Sean Adkinson Mar 13 '15 at 05:21
  • I think you're right, I have spoken to the BackEnd Developer, and he'll bring it out of the double-nest. So I will modify the question accordingly once it happens. The reason why I didn't show the iteration code is because I believed the initial state was causing the issue. However now the current problem is that I have to map inside a map while while building out the structure of a table. – johncho Mar 13 '15 at 14:22
  • My case is very similar to this http://stackoverflow.com/questions/25646502/how-to-render-repeating-elements – johncho Mar 13 '15 at 14:24
  • a very good explanation https://kirstyburgoine.wordpress.com/2018/01/21/iterating-through-json-data-in-react/ – Fabrizio Bertoglio Jan 08 '19 at 15:55

3 Answers3

3

I have had the same problem.

The reason why i got "Uncaught TypeError: undefined is not a function" was because i tried to iterate over the properties of a json object using map which is not possible. The solution for me was to iterate over the keys of the json object using Object.keys(). See below for my solution.

    Data: 
    {
        "status": {
            "build": {
                "a":"b",
                "c":"d"
            }
        }
    }   
       `render: function(){
            var buildInfo = this.props.applicationInfo.status.build;
            var properties = Object.keys(buildInfo).map((k, idx) => {
               return (
                 <p key={idx}><strong>{k}</strong> - {buildInfo[k]}</p>
               );
            });
            return(
                <div>
                    {properties}
                </div>
            );
        }`
linkebon
  • 401
  • 1
  • 4
  • 12
1

If you have JSON instead of Array and you want to loop in JSX react render function use Object.keys:

  <select className="form-control" >
   {Object.keys(item.unit).map(unit => {
      return <option value="1">1</option>
   })}
  </select>
0

So this works

<table className="table table-condensed table-striped">
    <thead>
        <tr>
            {resultTitles.map(function(title){
                var textAlignLeft = false;
                if(textLeftMatch.test(title)){
                     textAlignLeft = true;
                }
                title = title.replace(/_/g, " ");

                return <th key={title} className={textAlignLeft ? 'text-left' : ''}>{title}</th>
            })}
        </tr>
    </thead>
    <tbody>
        {resultData.map(function(tableRow, i) {
            return (
                <TableRow tableRow={tableRow} key={i} />
            );
        })}
    </tbody>
</table>

var TableRow = React.createClass({
    render: function(){
        var tableRow = this.props.tableRow;
        var rowArray = $.map(tableRow, function(value, index){
           return [value];
        });

        return(
                <tr key={tableRow}>
                    {rowArray.map(function(tableItem, i){
                        return <td key={i} className={(i === 0) ? 'text-left' : ''}>{tableItem}</td>
                    })}
                </tr>
        );
    }
});

However, after searching for awhile, I found a better starting point found here http://dynamictyped.github.io/Griddle/quickstart.html

johncho
  • 641
  • 2
  • 11
  • 25
  • 3
    While this answer is probably correct and useful, it is preferred if you include some explanation along with it to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. – Kevin Brown-Silva Mar 15 '15 at 21:18
  • 1
    You're right, I'll do a write up this week and keep this in mind for the future. – johncho Mar 16 '15 at 15:42
  • 1
    The comment by @KevinBrown makes more sense now that the link is not working anymore and I stuck with the same problem :( – gonephishing Dec 07 '17 at 17:00