javascriptloopswebfrontendtemplate-literals

How to make a JS foreach loop inside of a template literal block of HTML?


I have a block of HTML code that I'm repeating 9 times, each time modifying some of the classes and other stuff inside of it. Fot this, I'm using a JavaScript for loop containing a template literal as such:

for (let i = 0; i < 9; i++) {
    let controlDiv = document.createElement('div');
    controlDiv.setAttribute("class", "control" + i);

    controlDiv.innerHTML =  `
    <audio id="audio${+ i}" class="player${+ i}" src="audio/${defaultSounds[i]}.opus" loop></audio>
    <div class="on-off-container">
        <button onclick="onOff('audio${+ i}', 'btn-icon${+ i}','displaySpan${+ i}','on-off${+ i}')"type="button" class="on-off-btn btn-inactive on-off${+ i}">
             <i class="fa-solid fa-power-off"></i>
        </button>
    </div>
    `;
    
    document.getElementById("control-grid").appendChild(controlDiv);
}

This is a small sample of the total HTML code inside of the template literal but it communicates the essence of what I'm trying to do.

Now let's say that I have a JavaScript array as such:

const allSounds = ["Beachfront","Busy coffee shop","Busy restaurant"]

And I want to loop through it with a foreach loop, each time creating another HTML code block inside of the HTML that I'm already creating with the previous for loop:

for (let i = 0; i < 9; i++) {
    let controlDiv = document.createElement('div');
    controlDiv.setAttribute("class", "control" + i);
    controlDiv.innerHTML =  `
    <audio id="audio${+ i}" class="player${+ i}" src="audio/${defaultSounds[i]}.opus" loop></audio>

    allSounds.foreach {
        `[some more HTML to append to the DOM]`;
    }

    <div class="on-off-container">
        <button onclick="onOff('audio${+ i}', 'btn-icon${+ i}','displaySpan${+ i}','on-off${+ i}')"type="button" class="on-off-btn btn-inactive on-off${+ i}">
             <i class="fa-solid fa-power-off"></i>
        </button>
    </div>
    `;
    
    document.getElementById("control-grid").appendChild(controlDiv);
}

What would the correct syntax/way to do this be? I have tried putting the foreach loop inside of a ${} line but the curly braces get mixed up, and I have tried to cut the template literal block, execute the loop, and continue the block, but that doesn't work.


Solution

  • Use map() and join() to create an array of strings and then concatenate them.

        controlDiv.innerHTML =  `
        <audio id="audio${+ i}" class="player${+ i}" src="audio/${defaultSounds[i]}.opus" loop></audio>
    
        ${allSounds.map(sound => `some HTML to append`).join('')}
    
        <div class="on-off-container">
            <button onclick="onOff('audio${+ i}', 'btn-icon${+ i}','displaySpan${+ i}','on-off${+ i}')"type="button" class="on-off-btn btn-inactive on-off${+ i}">
                 <i class="fa-solid fa-power-off"></i>
            </button>
        </div>
        `;