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>