2
\$\begingroup\$

My problem is that when I try to make an app with a lot of buttons, I end up with a ton of global variables, a ton of DOM selectors and an equal amount of click functions that while simillar, I don't really understand how I could go about making a single function or how to approach it, surelly there has to be a much better way. I'll post 2 examples, I achieve the result I want, but my code is not pretty, at all:

http://codepen.io/Hyde87/pen/egOzLg?editors=1010

let count = 0;
const output = document.getElementById("output");
const gameResult = document.getElementById("gameResult");
const numbers = document.querySelectorAll(".each-number");
const numArray = Array.from(numbers);
const binaries = document.querySelectorAll(".binary-number");
const randomizer = document.getElementById("randomizer");
const oneHundredTwentyEight = document.getElementById("128");
const sixtyFour = document.getElementById("64");
const thirtyTwo = document.getElementById("32");
const sixteen = document.getElementById("16");
const eight = document.getElementById("8");
const four = document.getElementById("4");
const two = document.getElementById("2");
const one = document.getElementById("1");

oneHundredTwentyEight.addEventListener("click", function() {
  document.getElementById("binary-128").textContent = "1";
  addMyValue(128);
})
sixtyFour.addEventListener("click", function() {
  document.getElementById("binary-64").textContent = "1";
  addMyValue(64);
})
thirtyTwo.addEventListener("click", function() {
  document.getElementById("binary-32").textContent = "1";
  addMyValue(32);
})
sixteen.addEventListener("click", function() {
  document.getElementById("binary-16").textContent = "1";
  addMyValue(16);
})
eight.addEventListener("click", function() {
  document.getElementById("binary-8").textContent = "1";
  addMyValue(8);
})
four.addEventListener("click", function() {
  document.getElementById("binary-4").textContent = "1";
  addMyValue(4);
})
two.addEventListener("click", function() {
  document.getElementById("binary-2").textContent = "1";
  addMyValue(2);
})
one.addEventListener("click", function() {
  document.getElementById("binary-1").textContent = "1";
  addMyValue(1);
})

for (let i = 0; i < numArray.length; i++) {
  numArray[i].addEventListener("click", function()  {
    this.classList.add("light");
  })
}

function getRandom() {
  return Math.floor(Math.random() * (128 - 1 + 1)) + 1;
}

randomizer.addEventListener("click", () => {
  for (let i = 0; i < numArray.length; i++) {
    numArray[i].classList.remove("light");
  }

  for (let i = 0; i < binaries.length; i++) {
    binaries[i].textContent = "0";
  }

  gameResult.textContent = "";
  count = 0;
  output.textContent = getRandom();
})

const addMyValue = (num) => {
  count += num;
  console.log(parseInt(output.textContent));

  if (count > parseInt(output.textContent)) {
    gameResult.textContent = "Wrong value, you went over it."
    count = 0;
    output.textContent = "";
  } else if (count === parseInt(output.textContent)) {
    gameResult.textContent = "You got it right!";
    output.textContent = "";
  }
}

Another example of this:

http://codepen.io/Hyde87/pen/ObgadP

var outputArr = [];
var firstValue;
var secondValue;
var resetValues;
var totalNumber = document.getElementById("totalNumber");
var buttons = document.getElementsByClassName("col-xs-3");

var one = document.getElementById("one");
var two = document.getElementById("two");
var three = document.getElementById("three");
var four = document.getElementById("four");
var five = document.getElementById("five");
var six = document.getElementById("six");
var seven = document.getElementById("seven");
var eight = document.getElementById("eight");
var Nine = document.getElementById("nine");
var divide = document.getElementById("divide");
var multiply = document.getElementById("multiply");
var subtract = document.getElementById("subtract");
var comma = document.getElementById("comma");
var add = document.getElementById("add");
var equals = document.getElementById("equals");
var C = document.getElementById("C");
var back = document.getElementById("back");

/**************************************************************
EVENTLISTENERS
***********************************************************/
 zero.addEventListener("click", function(){
    getValue(0);
  });
 one.addEventListener("click", function(){
    getValue(1);
  });
 two.addEventListener("click", function(){
    getValue(2);
  })
 three.addEventListener("click", function(){
    getValue(3);
  })
  four.addEventListener("click", function(){
    getValue(4);
  })
 five.addEventListener("click", function(){
    getValue(5);
  })
 six.addEventListener("click", function(){
    getValue(6);
  })
  seven.addEventListener("click", function(){
    getValue(7);

  })
 eight.addEventListener("click", function(){
    getValue(8);
  })
 nine.addEventListener("click", function(){
    getValue(9);
  })
 comma.addEventListener("click", function(){
    getValue(".");


 /*****************************************************
 OPERANDS AND SPECIAL KEYS
 ****************************************************/
  })
add.addEventListener("click", function(){
   operation("+");
  })
multiply.addEventListener("click", function(){
  operation("*");
  })
subtract.addEventListener("click", function(){
  operation("-");
 })
divide.addEventListener("click", function(){
  operation("/");
 })
equals.addEventListener("click", function(){
  equalResult();
 })
C.addEventListener("click", function(){
  clear();
 })
 back.addEventListener("click", function(){
   backs();
 })



/* Function getValue() pushes the value of each click into the outputArr and displays in the totalNumber(which is the calculator display) the chain of numbers pressed*/
function getValue(value){
  outputArr.push(value);
  totalNumber.innerHTML += value;
}



/*The operation function is triggered by pressing +, -, *, /, it creates a value variable that gets the numbers inside the outputArr and joins them into a string (removing then the commas and creating a single value), we then empty the outputArr, we display the operand sign in the display and store the value in the firstValue global variable.*/ 
function operation(operand){
   var value = outputArr.join("");
   outputArr = [];
   totalNumber.innerHTML = operand;
 return firstValue = Number(value)
}




/* Function clear (C key) simply resets everything */
function clear (){
  totalNumber.innerHTML = " ";
  outputArr = [];
  return firstValue = 0;
}



/* The back function pops the last value we added and displays the outputArr as a joined string */
function backs (){
  outputArr.pop();
  totalNumber.innerHTML = outputArr.join("");
}



/* The equal result function assigns the value of the outputArr into the secondValue var, it then empties the outputArr and then it turns the string stored in secondValue into a number. Depending on the operand that is present in the display it performs one of the if/else possibilities. After that, the result in the display is stored in the outputArr as a number, also in the firstValue global var we store whatever number is in the display. Basically the result of firstValue and secondValue is stored as a firstValue again, so we re-use it. */
function equalResult(){
  var secondValue = outputArr.join("");
  outputArr = [];
  secondValue = Number(secondValue);
  if (totalNumber.innerHTML.indexOf("+") > -1) {
  totalNumber.innerHTML = firstValue + secondValue;
  } else if (totalNumber.innerHTML.indexOf("*") > -1){
  totalNumber.innerHTML = firstValue * secondValue;
  } else if (totalNumber.innerHTML.indexOf("/") > -1){
  totalNumber.innerHTML = firstValue / secondValue;
  } else if (totalNumber.innerHTML.indexOf("-") > -1){
  totalNumber.innerHTML = firstValue - secondValue;
  }
  outputArr.push(Number(totalNumber.innerHTML))
  console.log(outputArr)
  return firstValue = totalNumber.innerHTML;
  }
\$\endgroup\$
  • \$\begingroup\$ After posting this question and doing some research, I found out that using data attributes in HTML could be a good way to assign values to elements which would allow me to reference those values in my script and create a single function instead. \$\endgroup\$ – Sergi Jan 7 '17 at 17:14
2
\$\begingroup\$

Yes, you can do it using HTML data attributes. div elements even not needed classes. E.g. HTML:

<div class="binaries">     
  <p>
    <div data-id="128">0</div>
    <div data-id="64">0</div>
    <div data-id="32">0</div>
    <div data-id="16">0</div>
    <div data-id="8">0</div>
    <div data-id="4">0</div>
    <div data-id="2">0</div>
    <div data-id="1">0</div>      
    </p>
</div>

<div class="numbers">
  <p>
    <div data-id="128">128</div>
    <div data-id="64">64</div>
    <div data-id="32">32</div>
    <div data-id="16">16</div>
    <div data-id="8">8</div>
    <div data-id="4">4</div>
    <div data-id="2">2</div>
    <div data-id="1">1</div>      
  </p>
</div>

then binaries and numbers variables will be look like this:

const binaries = document.querySelectorAll('.binaries  div');
const numbers = document.querySelectorAll('.numbers  div');

then all you have to do is to add click event to all of numbers elemetnts → take dataset inside of it → search binary element with this data-id and change it textContent. Something like that:

const binaries = document.querySelectorAll('.binaries  div');
const decNumbers = document.querySelectorAll('.numbers  div');
const numArray = Array.from(decNumbers);

for (i = 0; i < numArray.length; i++) { 
  numArray[i].addEventListener('click', function() {    
    var id = this.dataset.id;
    document.querySelector('.binaries  div[data-id="' + id +'"]').textContent = "1";    
    addMyValue(id);
  });
}

Also you can dynamically all of your div, e.g.

let binariesWrap = document.querySelector('.binaries p');
for (let i = 0; i < 8; i++) {
  var pow = Math.pow(2,i);
  var div = document.createElement('div');
  div.dataset.id = pow;
  div.textContent = "0";
  binariesWrap.appendChild(div);  
  
  console.log(div);
}
.binaries div {
  display: inline-block;
  width: 50px;
  height: 50px;
  margin: 1.1%;
  font-size: 50px;
  line-height: 50px;
  border-radius: 100%;
  margin-bottom: -20px;
}
<div class="binaries">
  <p></p>
</div>

The same with numbers elements


Full code with a dynamic generating:

let count = 0;
const output = document.getElementById("output");
const randomizer = document.getElementById("randomizer");
const gameResult = document.getElementById("gameResult");
let binaries, numbers, numArray;

initData();

function initData() {
  let binariesWrap = document.querySelector('.binaries p');
  let numbersWrap = document.querySelector('.numbers p');

  for (let i = 0; i < 8; i++) {
    let pow = Math.pow(2, i);
    let div = document.createElement('div');
    let cln = div.cloneNode(true);
    div.dataset.id = cln.dataset.id = pow;
    div.textContent = "0";
    cln.textContent = pow;
    binariesWrap.appendChild(div);
    numbersWrap.appendChild(cln);
  }

  binaries = document.querySelectorAll('.binaries  div');
  decNumbers = document.querySelectorAll('.numbers  div');
  numArray = Array.from(decNumbers);
}


for (i = 0; i < numArray.length; i++) {
  numArray[i].addEventListener('click', function() {
    var id = this.dataset.id;
    document.querySelector('.binaries  div[data-id="' + id + '"]').textContent = "1";
    addMyValue(id);
  });
}


for (let i = 0; i < numArray.length; i++) {
  numArray[i].addEventListener("click", function() {
    this.classList.add("light");
  })
}

function getRandom() {
  return Math.floor(Math.random() * (128 - 1 + 1)) + 1;
}

randomizer.addEventListener("click", () => {
  for (let i = 0; i < numArray.length; i++) {
    numArray[i].classList.remove("light");
  }

  for (let i = 0; i < binaries.length; i++) {
    binaries[i].textContent = "0";
  }

  gameResult.textContent = "";
  count = 0;
  output.textContent = getRandom();
})


const addMyValue = (num) => {
  count += num;

  if (count > parseInt(output.textContent)) {
    gameResult.textContent = "Wrong value, you went over it."
    count = 0;
    output.textContent = "";
  } else if (count === parseInt(output.textContent)) {
    gameResult.textContent = "You got it right!";
    output.textContent = "";
  }
}
body {
  text-align: center;
  width: 100vw;
  height: 100vh;
  min-width: 530px;
  background: #D5D5D5;
}
.explanation {
  width: 70%;
  margin: 0 auto;
  margin-bottom: 40px;
}
.numbers div {
  display: inline-block;
  width: 50px;
  height: 50px;
  margin: 1%;
  border: 1px solid black;
  line-height: 50px;
  border-radius: 100%;
  background: white;
}
.binaries div {
  display: inline-block;
  width: 50px;
  height: 50px;
  margin: 1.1%;
  font-size: 50px;
  line-height: 50px;
  border-radius: 100%;
  margin-bottom: -20px;
}
.numbers div.light {
  transition: 500ms;
  background: #6D7993;
  color: white;
}
#randomizer {
  padding: 5px 20px;
}
#output {
  font-size: 30px;
  margin-top: 10px;
}
<body>
  <div class="wrap">
    <div class="explanation">
      <h3> The Binary Code Game </h3>
      <h4> A Javascript representation of the game as seen in Harvard's CS50 course. <br><br> First get a number (click the get a number button), then click the circles in order to sum the values  and match the number you got, without going over it. Once you get it right, what you actually see is a binary representation of that number. Clicking the same value twice negates the purpose of the game. </h4>
    </div>

    <div class="binaries">
      <p></p>
    </div>

    <div class="numbers">
      <p></p>
    </div>

    <button id="randomizer">Get a Number</button>
    <p id="output"></p>
    <h3 id="gameResult"> </h3>

  </div>
</body>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.