JSFiddle - React, Tailwind, and code Playground

by Serhii Matrunchyk

HTML

<script type="text/template" id="itemTpl">
	<div class="item">
  	<div class="name">{{name}}</div>
    <div class="qty">{{qty}}</div>
    <button class="btn-remove" @click="removeItem">Remove</button>
   </div>
</script>

<form autocomplete="off" class="form-item">
  <input id="name" />
  <span>x</span>
  <input type="number" min="1" id="qty" />
  <button id="btn-add">Add</button>
</form>

<div id="items" class="items"/>

CSS

.items {
  margin-top: 10px;
  border: gray solid;
  border-width: 1px 0 0 1px;
}

.item {
  display: grid;
  grid-template-columns: auto 50px 100px;
  border: gray solid;
  border-width: 0 1px 1px 0;
}

JavaScript

const addBtn = document.querySelector('#btn-add');
const itemsDiv = document.querySelector('#items');
const itemTpl = document.querySelector('#itemTpl').textContent;
const listeners = [];

const itemEvents = {
	remove(i) {
  	console.log(i);
  },
  
  edit(i) {
  	console.log(i);
  }
}

function grabValues() {
	return {
  	name: document.querySelector('#name').value,
    qty: document.querySelector('#qty').value,
  }
}

function injectValues(data) {
  // https://regex101.com/r/17Bu0k/1
	return itemTpl.replace(/{{(.*?)}}/g, (i, match) => data[match]);
}

function rememberEventListeners(tpl) {
	// https://regex101.com/r/8mcKYE/1
	return tpl.replace(/@([\w]+?)="([\w]+?)"/g, (i, event, listener) => {
		listeners.push({
    	id,
    	event,
      listener,
    });
    return `data-action-id="${id}"`;
  });
}


function compileTemplate(data) {
	return rememberEventListeners(injectValues(data));
}


function renderItem(compiledTpl) {
	itemsDiv.insertAdjacentHTML('beforeend', compiledTpl);
  return itemsDiv.querySelector('.item:last-child');
}

function clearForm() {
	document.querySelector('#name').value = '';
  document.querySelector('#qty').value = '';
}

function bindEvents(el) {
	listeners.forEach(({ id, event, listener }) => {
	  const srcEl = el.querySelector(`[data-action-id="${id}"]`);
  	srcEl.addEventListener(event, itemEvents[listener]);
  });
}

function addItem(e) {
	e.preventDefault();
  
  const data = grabValues();
  const compiledTpl = compileTemplate(data);
  const itemDiv = renderItem(compiledTpl);
  console.log(listeners);
  bindEvents(itemDiv);
  clearForm();
}

addBtn.addEventListener('click', addItem);