2

I have a html markup for a list

<ul>
    <a id="catalogPlaceholder"></a> <!-- this is the placeholder to append new items -->

    <a class="sidebarListItem" href="#link">        
        <object type="deleteLinkOnHover"><a class="deleteItem" href="javascript:deleteItemFromList()">Delete</a></object>
        <div style="width:30%;float:left; background: none"><img class="rounded-circle" src="#image" alt="Product image" width="100%"></div>
        <div style="float:left;padding-left:10px;width:60%;background: none"><strong class="text-muted d-block mb-2"><h5>#title</h5></strong></div>        
    </a>
    <a class="sidebarListItem" href="#link">        
        <object type="deleteLinkOnHover"><a class="deleteItem" href="javascript:deleteItemFromList()">Delete</a></object>
        <div style="width:30%;float:left; background: none"><img class="rounded-circle" src="#image" alt="Product image" width="100%"></div>
        <div style="float:left;padding-left:10px;width:60%;background: none"><strong class="text-muted d-block mb-2"><h5>#title</h5></strong></div>        
    </a>
    <a class="sidebarListItem" href="#link">        
        <object type="deleteLinkOnHover"><a class="deleteItem" href="javascript:deleteItemFromList()">Delete</a></object>
        <div style="width:30%;float:left; background: none"><img class="rounded-circle" src="#image" alt="Product image" width="100%"></div>
        <div style="float:left;padding-left:10px;width:60%;background: none"><strong class="text-muted d-block mb-2"><h5>#title</h5></strong></div>        
    </a>
</ul>

that looks like this image

and want to add new items using javascript like this

function relateNewCatalog(id, image, title) {
    var a = document.createElement('a');
    a.classname = "sidebarListItem";
    a.id = "sidebarItemCatalog-" + id;
    a.href = "../?module=catalogDetails&idcatalog=" + id;
    a.style = "padding:10px";
        
    var html = '<object type="deleteLinkOnHover"><a class="deleteItem" href="javascript:deleteItemFromList(\'sidebarItemCatalog-' + id +  '\')">Delete</a></object>';
    html += '<div style="width:30%;float:left; background: none"><img class="rounded-circle" src="../uploads/images/' + image + '" alt="Product image" width="100%"></div>';
    html += '<div style="float:left;padding-left:10px;width:60%;background: none"><strong class="text-muted d-block mb-2"><h5>' + title + '</h5></strong></div>';        

    a.innerHTML = html;
    var placeholder = document.getElementById("catalogPlaceholder");
    placeholder.append(a);
} 

but the markup seems broken when I do so like in this image (see padding and hover effect). I tried clear:both and also with insertBefore instead of appendChild but without success. The more items I add the more they get stacked like in the last image

Thanks for your time!

MBrain
  • 25
  • 8

1 Answers1

2

You can use <template> and separate data and view as follows

let data = [
  { id: 1, title: 'Product 1', image: "https://picsum.photos/id/10/50" },
  { id: 2, title: 'Product 2', image: "https://picsum.photos/id/20/50" },
  { id: 3, title: 'Product 3', image: "https://picsum.photos/id/30/50" }
]

function refresh() {
  let r='', inj = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);
  for(let it of data) r += inj(item.innerHTML,it);
  catalogPlaceholder.innerHTML = r;
}

function relateNewCatalog() {
  data.unshift({
    id: Math.max(...data.map(x=>x.id),0)+1, 
    title: `Product ${data.length+1}`, 
    image: `https://picsum.photos/id/${Math.random()*300|0}/50` 
  });
  refresh();
}

function deleteItemFromList(id) {
  data = data.filter(x=> x.id!=id);
  refresh();
}

refresh();
.sidebarListItem {display: flex}
h5 {margin:0}
<button onclick="relateNewCatalog()">Add</button>
<ul id="catalogPlaceholder" ></ul>

<template id="item" >
  <li>
    <a class="sidebarListItem" href="#link">        
      <object type="deleteLinkOnHover">
        <a class="deleteItem" onclick="deleteItemFromList(${id})">Delete</a>
      </object>
      <div class="imgBox">
        <img class="rounded-circle" src="${image}" alt="Product image" >
      </div>
      <div class="titleBox"><strong class="text-muted d-block mb-2">
        <h5>${title}</h5>
      </strong></div>        
    </a>
  </li>
</template>
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • Nicely presented! Although, you are rebuilding the whole page every time you add another catalogue. This could slow down the page or cause some flickering when there is a large number of catalogues to list. So, maybe `.appendChild()` might come in as a useful alternative to `innerHTML`? (@MBrain: there is no "an" before "useful" ;-) ) – Carsten Massmann Jun 05 '19 at 05:36
  • @cars10m you are right - the solution can be improved to not change old products in html tree. By the way in past I made some tests [here](https://stackoverflow.com/a/55970947/860099) and it looks lie `innerHTML =` (do not confuse with `+=` !) is faster than `.appendChild()` - – Kamil Kiełczewski Jun 05 '19 at 05:52
  • Sorry @MBrain, my wife (English native speaker and professional translator) is looking over my shoulder and is slowly losing the will to live ... The use of "a" or "an" depends solely on the pronunciation of the immediately following word. The word "alternative" is of no relevance here. – Carsten Massmann Jun 05 '19 at 06:00
  • 1
    Hi @Kamil, interesting fact about your speed comparison. Will remember that for future projects. You got my +1 already this morning. I hope MBrain is not too cross about my comments and will accept your answer. ;-) – Carsten Massmann Jun 05 '19 at 18:24