7

I want to crate HTML in for loop in JSX. Here is what my try look likes

    function renderTemplates(templates){
           var html = [];
           var templateDiv = [];
           var count  = 0;
           for(var identifier in templates){  
             if(templates.hasOwnProperty(identifier)){
               var templateDetails = templates[identifier];
               if(count == 0){
                  html.push(<Row>);
               }
               cols = <Col md={6}>ff
                          </Col>;
               html.push(cols);
               if(count == 0){
                      html.push(</Row>);
               }
               count = (count === 1)?0:1;
             }
        } 
        return html;
     }

I know this is wrong syntax but can't figure out how to do it. Basically I have some data and want to create html in fashion that 2 divs lies horizontaly in 1 row.

2
  • Can anybody give me suggestion ? Commented Feb 24, 2015 at 16:55
  • Could you give example data of what templates value and the corresponding value expected for html? Commented Feb 27, 2015 at 22:10

2 Answers 2

4

On a recent project I did something similar, but with table rows/columns.

var TableBody = React.createClass({
  render: function(){
    var columns = this.props.columns;
    var data = this.props.data;

    return (
      <tbody>
        {data.map(function(item, idx){
          return <TableRow key={idx} data={item} columns={columns}/>;
        })}
      </tbody>
    )
  }
});

My <TableRow /> component looks like:

var TableRow = React.createClass({
  render: function() {
    var columns = this.props.columns;
    var data = this.props.data;
    var td = function(item) {

        return columns.map(function(c, i) {
          return <td key={i}>{item[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr key={data}>{ td(data) }</tr>
    )
  }
});
Sign up to request clarification or add additional context in comments.

Comments

2

Two things jump out at me when I look at your code.

The first is that you are returning an array of React components from the renderTemplates function. This may be okay depending on how you use the output. The key to remember is that the return value from your component's render function must be a single React component (e.g., if you wrap this result in another JSX tag, you're okay.)

Secondly, it appears that you are not letting data flow from the top-level component on down; specifically, that you do not use the Row component to pass data to Column components. This is what makes writing your loop so difficult. Instead of trying to manage both Rows and Columns, you need only to pass the data needed for a single row to a Row component. The Row component will then pass each piece of data to a Column component. This removes the need to juggle opening and closing tags and simplifies the code overall.

Following is an example implementation of what I have described. I use table-related tags for rendering, but you can use divs or whatever is most appropriate for you. At the time of writing, there isn't much information about what is in templates, so I've created a silly little example to use.

var KvpColumn = React.createClass({
    render: function() {
        return <td>{this.props.kvp.key}: {this.props.kvp.value}</td>;
    }
});

var KvpRow = React.createClass({
    render: function() {
        return (
            <tr>
            {this.props.items.map(function(item) {
                return <KvpColumn key={item.key} kvp={item}/>;
            })}
            </tr>
        );
    }
});

var ObjectIDsTable = React.createClass({
    render: function() {
        var templates = this.props.templates;

        var propertyNames = Object.getOwnPropertyNames(templates);
        var group = [];
        var rows = [];
        var cols = Number(this.props.cols) || 2;

        for(var i = 0; i < propertyNames.length; i++) {
            var key = propertyNames[i];

            group.push({key: key, value: templates[key]});
            if(group.length === cols) {
                rows.push(<KvpRow key={group[0].key} items={group}/>);
                group = [];
            }
        }

        if(group.length > 0) { // catch any leftovers
            rows.push(<KvpRow key={group[0].key} items={group}/>);
        }

        return <table>{rows}</table>;
    }
});    

// something silly as a simple example
var templates = { a: 'b', c: 'd', e: 'f', g: 'h', i: 'j' };    
React.render(<ObjectIDsTable templates={templates} cols="2"/>, document.getElementById('app'));

If you have access to Underscore or lodash, you can simplify the logic in ObjectIDsTable a bit further (and avoid writing loops altogether!):

var ObjectIDsTable = React.createClass({
    render: function() {
        var templates = this.props.templates;

        var rows = _.chain(Object.getOwnPropertyNames(templates))
            .map(function(key) { return { key: key, value: templates[key] }; })
            .chunk(this.props.cols || 2)
            .map(function(group) { return <KvpRow key={group[0].key} items={group}/>; })
            .value();

        return <table>{rows}</table>;
    }
});

You can see this in action on Plunker.

Comments

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.