1

I'm having trouble getting a component to render within .map

render: function() {

  var self = this;

  var ListItems = this.props.data.map(function(data){
      self.props.fields.forEach(function(field, i) {
          if (field.fieldKey in data) {
              console.info(field.fieldKey + ': ' + data[field.fieldKey]);
              return (<ListItem {...data} key={'field-' + i}/>)
          } else {
              console.error(field.fieldKey + " doesn't exist. Please make sure you match your 'fieldKey' to an existing column in your data table");
          }
      });
  });


return <tr onDoubleClick={this.handleEditRow} onClick={this.handleSelectRow}>
    {ListItems}
    <td className="text-center">
        <span className="btn"><input type="checkbox" ref="deleteCheckbox" checked={this.props.checked} onChange={this.handleDeleteChange}/></span>
        <a className="btn" onClick={this.handleDeleteRow} title="Delete this Item"><i className="md md-close"></i></a>
    </td>
</tr>
  },

So my ListItem doesn't show at all. If I move it under the first loop, it shows fine. Can anyone tell me what I'm doing wrong?

UPDATES

JSON DATA

http://pastebin.com/MLbR77tG

So, I'm creating a list view. Basically, each item under data has a fields setting attached via the fieldKey

So the plan is to spit out the data, but use the configuration options under fields to format the list view. i.e. fieldKey is a dropdown, it's dataSource is message yada yada.

Name(data: test 1) (fields: is dropdown) | calling_gt(data: 123456) (fields: is text) | op_code (data: 5678) (fields: is dropdown)

5
  • 1
    this.props.data.map you didn't return anything from this. This return (<ListItem {...data} key={'field-' + i}/>) is in self.props.fields.forEach, not in map scope. Commented Dec 7, 2015 at 8:50
  • It's supposed to be. Basically that second inner loop checks if it exists in another array before printing the ListItem. But what I'm not understanding is why it won't return anything that's inside that second loop. Commented Dec 7, 2015 at 8:56
  • 1
    Because forEach do Not return anything, or in other words, in returns undefined. Commented Dec 7, 2015 at 8:57
  • I don't think I get you. The console.log within forEach prints out the correct info Commented Dec 7, 2015 at 8:58
  • You can remove that console.log, and then rewrite as var xxx = self.props.fields.forEach...., then console.log(xxx) to see that it did returns nothing. Commented Dec 7, 2015 at 8:59

2 Answers 2

3

Check out Array.prototype.forEach() - MDN

forEach() executes the callback function once for each array element; unlike map() or reduce() it always returns the value undefined and is not chainable. The typical use case is to execute side effects at the end of a chain.

For example, check out this jsfiddle. When you return a value within forEach() method, the value will not be received by the outer function, in this case, map loop. Instead, the outer loop will always get a undefined from the forEach() loop.

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

1 Comment

So forEach is the wrong one to use. The same happens if I switch it to map though. I guess I'm not understanding the why...
0

Your return statement is inside the call to forEach meaning it can't affect the outer map statement.

This means that the map function is returning undefined each time, which is why the component doesn't render.

Instead, you can write a predicate function that you can use to filter out rows that aren't used.

hasValidFieldKeys: function(fields, data) {
  var invalidFields = fields.filter(function(field) {
    var hasKey = field.fieldKey in data;

    if(!hasKey) {
      // log error
    }

    return !hasKey;
  });

  return invalidFields.length > 0;
}

Then use the predicate function inside component's render method.

var ListItems = this.props.data
  .filter(function(data) {
    // remove the rows that aren't valid
    return self.hasValidFieldKeys(self.props.fields, data);
  })
  .map(function(data, index) {
    return data.map(function(data, index2) {
      var compositeKey = 'field-' + index + ':' + index2; 
      return <ListItem {...data} key={compositeKey}/>;
    });
  });

If it's important that your app stops if there is data missing certain field keys, then throw errors, rather than using console.error.

6 Comments

I think the issue is with return (<ListItem {...data} key={'field-' + index}/>); This still pulls out all the rows from data. That's why originally I had ListItem within the loop that does the check.
Maybe I've misunderstood, should there be a <ListItem /> for each item in data, or for each field in each item in data?
Each item in field that exists in data, but outputting the value from data using the fieldKey as a reference. Updated example above:
I can output the correct info with console.log data[field.fieldKey] in the loop
Updated question to add a second map.
|

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.