Vanilla JS to dynamically add or remove div boxes

Tags:



When checking on the checkbox i’m trying to create the div boxes and when unchecking remove it dynamically.

I know with React i could do this in 2min but i’m trying to learn Vanilla JS way

Current issues i’m having:

  1. When checking on checkbox it renders more elements than one
  2. When unchecking checkbox for example all one element is still rendered.

END GOAL: dynamically add and remove Div boxes depending on what is in state variable, (console.log that its outputting should give guidance on how correctly it should look) but also making sure no extra boxes are being used / rendered.

window.onload = () => {
  const checkbox = document.querySelectorAll('.checkbox')
  let state = []

  for (idx of checkbox) {
    idx.addEventListener('change', (e) => {
      if (e.currentTarget.checked === true) {
        state.push(e.currentTarget.id)
        renderOnDom(state, 'add', e.currentTarget.id) // Experimenting
      }
      if (e.currentTarget.checked === false) {
        state = state.filter((item) => item !== e.currentTarget.id)
        renderOnDom(state, 'remove', e.currentTarget.id) // Experimenting
      }
      console.log('state', state)
    })
  }
}

const renderOnDom = (el, option, id) => {
  if (option === 'add') {
    el.map((item, idx) => {
      const div = document.createElement('div')
      div.setAttribute('key', item)
      div.className = 'test'
      div.innerHTML = `Box ${item}`
      document.querySelector('#projects').appendChild(div)
    })
  }

  if (option === 'remove') {
    const test = document.querySelectorAll('.test')
    const prod = document.querySelector('#projects')
    for (const iterator of test) {
      if (iterator.attributes.key.value === id) {
        prod.removeChild(prod.firstChild)
      }
    }
  }
}
<input id="id1" data="name1" class="checkbox" type="checkbox" />
      <label for="id1">Test 1</label>

      <input id="id2" data="name2" class="checkbox" type="checkbox" />
      <label for="id2">Test 2</label>

      <input id="id3" data="name3" class="checkbox" type="checkbox" />
      <label for="id3">Test 3</label>

      <div id="projects"></div>

Answer

Hey I have updated your snippet to do what I think you want to do.

In a nutshell, the source of truth is state array. So after any changes to it, reset the dom using resetDom() and then fire renderOnDom().

window.onload = () => {
  const checkbox = document.querySelectorAll('.checkbox')
  let state = []

  for (idx of checkbox) {
    idx.addEventListener('change', (e) => {
      if (e.currentTarget.checked === true) {
        state.push(e.currentTarget.id)
      }
      if (e.currentTarget.checked === false) {
        state = state.filter((item) => item !== e.currentTarget.id)
      }
      renderOnDom(state, e.currentTarget.id)
    })
  }
}
const resetDom = () => {
  const projects = document.querySelector("#projects");
  while (projects.firstChild) {
    projects.removeChild(projects.firstChild)
  }
}
const renderOnDom = (el, id) => {
  resetDom();
  el.forEach((item, idx) => {
    const div = document.createElement('div')
    div.setAttribute('key', item)
    div.className = 'test'
    div.innerHTML = `Box ${item}`
    document.querySelector('#projects').appendChild(div)
  })

}
<input id="id1" data="name1" class="checkbox" type="checkbox" />
<label for="id1">Test 1</label>

<input id="id2" data="name2" class="checkbox" type="checkbox" />
<label for="id2">Test 2</label>

<input id="id3" data="name3" class="checkbox" type="checkbox" />
<label for="id3">Test 3</label>

<div id="projects"></div>


Source: stackoverflow