A.Vincent
A.Vincent

Reputation: 267

How to start a component in a loop and close it all 3 iterations

Hello i search solution for open tag in loop and close it all the 3 iteration. The goal is to create a grill based on container row and col. My problem is I do not know how to do.

Exemple :

    render(){
        const arrayName = ["john", "bob", "joe", "mat", "toto", "tata"]
        let arrayEl = [];
        let count = 1; 
          for ( let i = 0; i < arrayName.length; i++ ) {
             let name = arrayName[i]

             if (count === 1) {
                 arrayEl.push(<div className="row">);
                 arrayEl.push(<p className="col">{name}</p>);
                 count ++;
                 continue;
             }
             if (count === 3) {
                 arrayEl.push(<p className="col" >{name}</p>);
                 arrayEl.push(</div>);
                 count = 1;
                 continue;
             }
           }
        return (<div className="container">{arrayEl}</div>)
    }

and the result wanted is :

<div className="container">
    <div className="row">
        <div className="col">john</div>
        <div className="col">bob</div>
        <div className="col">joe</div>
    </div>
    <div className="row">
        <div className="col">mat</div>
        <div className="col">toto</div>
        <div className="col">tata</div>
    </div>
</div>

thank you for some help

EDIT

The problem is we can't add someone element or componant without close it.

is Bad :

arrayEl.push(<div className="row">)

is good :

arrayEl.push(<div className="row"/>) or arrayEl.push(<div className="row"></div>)

Upvotes: 0

Views: 68

Answers (4)

Daan
Daan

Reputation: 2799

You can't push HTML elements in parts, e.g.

arrayEl.push(<div>)

arrayEl.push(</div>)

You have to push the elements from start to end, e.g.

arrayEl.push(<div>{children}</div>)

Therefor you need to instantly output all cols in row, like the code example below.

render() {
    const arrayName = ["john", "bob", "joe", "mat", "toto", "tata"];
    let rows = [];
    let currentCols = [];

    for (let i = 0; i < arrayName.length; i++) {
        let name = arrayName[i];
        currentCols.push(<div className="col" key={i}>{name}</div>);

        if ((i+1) % 3 === 0) {
          rows.push(<div className="row" key={i}>{currentCols}</div>);
          currentCols = [];                
        }
    }

    rows.push(currentCols);
    return (<div className="container">{rows}</div>)
}

JSFiddle demo

Instead of using a count variable, I just used the i variable from your loop and checked whether or not (i + 1) is dividable by 3: % 3 === 0. If that is the case, it means you already have 3 cols in your row; We can push the currentCols to the rows array and empty it.

Upvotes: 1

Pietro Nadalini
Pietro Nadalini

Reputation: 1800

Ok, so you have to change the logic on your loop in order to get the result you want. Here's what I made as an example with JavaScript. You just need to adapt it with your component.

const arrayName = ["john", "bob", "joe", "mat", "toto", "tata"];
let arrayEl = [];

for (let i = 0; i < arrayName.length; i++) {
  let name = arrayName[i];
  if ((i % 3) == 0) {
    arrayEl.push(`<div className = "row">\n`);
  }
  arrayEl.push(`<p className = "col">${name}</p>\n`);
  if (((i + 1) % 3) == 0) {
    arrayEl.push(`</div>\n`);
  }
}
console.log(`<div className="container">\n ${arrayEl.join(' ')}</div>`);

Upvotes: 0

Yury Tarabanko
Yury Tarabanko

Reputation: 45106

The problem with your approach is that JSX is not html so </div> expression is invalid.

Imperative approach for the sake of completeness. :)

BTW you need keys.

render(){
    const arrayName = ["john", "bob", "joe", "mat", "toto", "tata"]
      let arrayEl = [];
      let row = [];
      const batchSize = 3
      for ( let i = 0, i < arrayName.length, i++ ) {
         const name = arrayName[i]
         row.push(<div className="col" key={name}>{name}</div>)

         // we have a full batch or the last element 
         if (row.length === batchSize || i === arrayName.length - 1) { 
           arrayEl.push(<div className="row" key={i/batchSize}>{row}</div>)
           row = []
         }
       }
    return (<div className="container">{arrayEl}</div>)
}

Upvotes: 0

kigiri
kigiri

Reputation: 3368

I would change your data from:

 ["john", "bob", "joe", "mat", "toto", "tata"]
// to
 [["john", "bob", "joe"], ["mat", "toto", "tata"]]

Checkout https://lodash.com/docs/4.17.11#chunk for example of that

And then you can nest 2 .map to replicate the structure in JSX:


const chunk = (arr, chunckSize) => arr.reduce((chunks, value, index) => {
  const chunckIndex = Math.floor(index / chunckSize)
  const c = chunks[chunckIndex] || (chunks[chunckIndex] = [])
  c.push(value)
  return chunks
}, [])

render() {
    const arrayName = ["john", "bob", "joe", "mat", "toto", "tata"]

    return (
        <div className="container">
            {chunk(arrayName, 3).map(names => (
                <div className="row">
                    {names.map(name => <div className="col">{name}</div>)}
                </div>
            ))}
        </div>
    )
}

Upvotes: 1

Related Questions