Any way to duplicate elements to prevent repetitive code in HTML?

Viewed 161

I'm sorry this is probably a silly question, but I'm writing out a restaurant menu page, and want to create some way to display multiple food items/descriptions in a grid-like (3x5) pattern onto the page without manually coding out 15 nearly identical divs for each one.

Any help or solution would be amazing!

<div class="menu-column-wrapper">
            <div class="menu-column">
                <div class="menu-item">
                    <div class="item-header">
                        <h3>Item</h3>
                    </div>

                    <div class="item-description">
                        <p>Description</p>
                    </div>
                </div>

This is how I currently have this menu section set up, with 3 separate "menu-column" divs, each containing 5 nested "menu-item" divs.

Thanks guys!

4 Answers

You can solve that with the code below.

Basically, it's solved in javascript using template literals.

index.html

<html lang="en">
 <head>
  <script src="index.js"></script>
 </head>
 <body>
  <div class="menu-column-wrapper" />
 </body>
</html>

index.js

document.addEventListener('DOMContentLoaded', (event) => {
  const menuItem = `
    <div class="menu-item">
    <div class="item-header">
      <h3>Item</h3>
     </div>
    <div class="item-description">
      <p>Description</p>
    </div>
  </div>
  `
  const menuColumn = `
    <div class="menu-column">
      ${menuItem}
      ${menuItem} 
      ${menuItem} 
      ${menuItem} 
      ${menuItem} 
    </div>
    `
  const menuColumnWrapper = document.querySelector('.menu-column-wrapper');
  menuColumnWrapper.innerHTML = `
    ${menuColumn}
    ${menuColumn}
    ${menuColumn}
  `
});

You can use an html engine like handlebars or ejs etc... With handlebars your html code will lock something like :

<div class="menu-column-wrapper">
   {{#each food}}
    <div class="menu-column">
         <div class="menu-item">
              <div class="item-header">
                   <h3>{{this.Item}}</h3>
              </div>
              <div class="item-description">
                 <p>{{this.Description}}</p>
              </div>
         </div>
    </div>
   {{/each}}
</div>

with js array :

food [
   {Item: 'item1', Description: 'desc1'},
   {Item: 'item2', Description: 'desc2'},
   {Item: 'item3', Description: 'desc3'}
]

You can use grid or flex-box. Here's a grid example.

.menu-column-wrapper {
  display: grid;
  grid-template-columns: auto auto auto;
  grid-template-rows: auto auto auto auto auto;
  width: min-content;
  height: auto;
  border: 1px grey solid;
}
.menu-item {
  position: relative;
  width: auto;
  height: auto;
  padding: 0 20px 0 20px;
  text-align: center;
  border: 1px grey solid;
}
h3 {
  white-space: nowrap;
}
img {
  width: 75px;
  height:auto;
}
p {
  font-size: 9pt;
}
<div class="menu-column-wrapper">
  <div class="menu-item">
    <h3>Chicken Pot Pie</h3>
    <img src="https://dinnerthendessert.com/wp-content/uploads/2015/08/Chicken-Pot-Pie-3.jpg" alt="pie"/>
    <p>This is a description of some food. It has chicken and carrots.</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Chicken Curry</h3>
    <img src="https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/190509-coconut-chicken-curry-157-1558039780.jpg?crop=0.668xw:1.00xh;0.116xw,0&resize=480:*" alt="curry"/>
    <p>This is a spicy dish served over rice. Includes peppers and carrots.</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
  <div class="menu-item">
    <h3>Item</h3>
    <p>Description</p>
  </div>
</div>

The thin framework below should dynamically create a skeleton page and populate it with the specified information as you're requesting. I don't know the name of your CSS file, so you'll obviously have to include that, but this should show you how to dynamically construct a page containing some unknown number of approximately-identical internal structures on the fly:

JSFiddle: https://jsfiddle.net/zk3th8j9/1/

<html>
    <head>
        <script language='javascript'>
        var menu = [
            [ "item0", "desc0" ], [ "item1", "desc1" ], [ "item2", "desc2" ], // row 1
            [ "item3", "desc3" ], [ "item4", "desc4" ], [ "item5", "desc5" ], // row 2
            [ "item6", "desc6" ], [ "item7", "desc7" ], [ "item8", "desc8" ], // row 3
            [ "item9", "desc9" ], [ "itemA", "descA" ], [ "itemB", "descB" ], // row 4
            [ "itemC", "descC" ], [ "itemD", "descD" ], [ "itemE", "descE" ], // row 5
        ];

        function CreateBasicDiv( className )
        {
            var div = document.createElement( "div" );
    
            div.className = className;
            // optional: assign any other DIV parameters you need/want...
    
            return div;
        }

        function CreateItemDiv( item, desc )
        {
            var div = [], classes = [ "menu-column-wrapper", "menu-column", "menu-item", "item-header", "item-descripton" ];

            // iteratively create a series of <DIV> elements with proper classNames
            for( var i = 0; i < classes.length; i++ )
                div[ i ] = CreateBasicDiv( classes[ i ] );

            // consider putting the 'h3' styling into the CSS, or the 'item' string itself
            div[ 3 ].innerHTML = "<h3>" + item + "</h3>";

            // likewise, the <p>aragraphing should probably be done within the 'desc' string...
            div[ 4 ].innerHTML = "<p>" + desc + "</p>"

            div[ 2 ].appendChild( div[ 3 ] );
            div[ 2 ].appendChild( div[ 4 ] );

            // 'nest' the div's...
            for (var i = 2; i > 0; )
               div[ i-1 ].appendChild( div[ i-- ] );

            return div[ 0 ];
        }

        function CreateMenu()
        {
            var table = document.createElement( "table" ), 
                colCount = 3, i = 0, width = Math.round( 90 / colCount );

            // Override class definitions for these settings:
            table.style = "position:relative;width:90%;left:5%;top:50px;table-layout:fixed;";

            while ( i < menu.Length )
            {
               var tr = document.createElement( "tr" );
               do {
                  var td = document.createElement( "td" );
                  td.style.width = width + "%"; // <-- enforce cell width
                  td.appendChild( CreateItemDiv( menu[ i ][0], menu[ i ][1] ) );
                  tr.appendChild( td );
               } while ( (++i < menu.length) && (i % colCount > 0) )
               table.appendChild( tr );
            }
            document.body.appendChild( table );
        }
        </script>
    </head>
    <body onload='CreateMenu();'></body>
</html>
Related