Skip to content
Advertisement

How to create an event that when a div or it’s child elements clicked create a border around the whole div in vanilla Javascript

I have a container and inside of it I dynamically create divs. Every created div has 2 p elements inside. How can I add an onclick function in every created div so when click either the div or the p elements a green border appears only around the WHOLE div. Because now if I click a p the border is around p and not around the div. I must click the div to get the right border.

Also when a div is clicked the program iterates an array of objects with the right answers and if the clicked div’s id is in the arrays code3 value I want to add to the div a green border. In case of wrong a red border. With the code I have, in case the right answers are more than one, only one Right answer takes the green border and the other Right answers take the red border like the wrong ones. Also in the console when I click a right answer the country name appears (as it should) but also appears the “Wrong” word below the name, with a small number to the left. Is something wrong with my for-loop? My code is:

<body>
<div class = "game-panel">
  <div id="neighbours-panel">
    <div class= neighbor id='ARG'>
         <p>AR(Flag symbol)</p>
         <p>Argentina</p> 
    </div>
    <div class= neighbor id='ITA'>
         <p>IT(Flag symbol)</p>
         <p>Italy</p> 
    </div>
    <div class= neighbor id='GRC'>
         <p>GR(Flag symbol)</p>
         <p>Greece</p> 
    </div>
    etc.
    .
    .
    .
   </div>
</div>

//An array of countries:
realNeighbours = [{ "code": "AF", "code3": "AFG", "name": "Afghanistan", "number": "004" },     { "code": "DZ", "code3": "DZA", "name": "Algeria", "number": "012" },     { "code": "AS", "code3": "ASM", "name": "American Samoa", "number": "016" },     { "code": "AD", "code3": "AND", "name": "Andorra", "number": "020" },]

//JS code:
x = document.getElementById("game-panel").childNodes;

x[x.length-1].addEventListener("click", function (e) {
  for(i=0; i<realNeighbours.length; i++){
    if(realNeighbours[i]['code3'].includes(e.target.id)) {
      e.target.style.border = '1px solid green';
      console.log(this.innerHTML);
    } else {
      e.target.style.border = '1px solid red';
      console.log('wrong')
    }
  }
});

Advertisement

Answer

you don’t need to create an eventListener on each added div, use the event delegation technique

const
    DomParser = new DOMParser()
  , Checked_HTML = str => (DomParser.parseFromString( str, 'text/html')).body.firstChild
  , borderCountries =
      [ { code: 'AR', code3: 'ARG', name: 'Argentina'   } 
      , { code: 'AF', code3: 'AFG', name: 'Afghanistan' } 
      , { code: 'IT', code3: 'ITA', name: 'Italy'       } 
      , { code: 'GR', code3: 'GRC', name: 'Greece'      } 
      ] 
  , realNeighbours = 
    [ { code: 'AF', code3: 'AFG', name: 'Afghanistan',    number: '004' } 
    , { code: 'DZ', code3: 'DZA', name: 'Algeria',        number: '012' } 
    , { code: 'AS', code3: 'ASM', name: 'American Samoa', number: '016' } 
    , { code: 'AD', code3: 'AND', name: 'Andorra',        number: '020' } 
    ] 
  , gamePanel = document.querySelector('div#game-panel') 
  , score = (function ()  // IIFE clossure
    {
    let divCount = 0
      , value    = 0
      ;
    const
        counter  = document.querySelector('#score > span')
      , correct  = +5
      , wrong    = -3
      , obj = 
        { update(bool)
          {
          value +=( bool ? correct : wrong) * divCount
          counter.textContent = value
          }
        , divAdded() { divCount++ }
        }
      ;
    counter.textContent = value  // init  
    return obj
    })()
  ;
gamePanel.onclick = evt =>
  {
  if (!evt.target.matches('div.neighbor, div.neighbor > p') ) return
  let xDiv    = evt.target.closest('div.neighbor')
    , test_c3 = realNeighbours.some(el=>el.code3===xDiv.dataset.code3)

  score.update(test_c3)
 
  xDiv.classList.add( (test_c3 ? 'cl_green' : 'cl_red') )
  }
 
// generate the divs --- (with DOMParser(): personal preference) 
borderCountries.forEach( bc => 
  {
  let newDiv = `
  <div class="neighbor" data-code3="${bc.code3}">
    <p>${bc.code}(Flag symbol)</p>
    <p>${bc.name}</p> 
  </div>`
  gamePanel.appendChild(Checked_HTML(newDiv)) 

  score.divAdded()
  })
div#game-panel > div { border: 3px solid transparent }
div#game-panel > div.cl_red   { border-color: red;}
div#game-panel > div.cl_green { border-color: green;}
<h4 id="score">score <span></span></h4>

<div id="game-panel">
</div>
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement