I want to set value="a" depending on the condition it meets. Button has no value attribute currently. How do I write this?I want like this <button value="a"> One </button>
const buttonValues = ["a", "b"]
const addingValuesToButtons = () => {
for (var i = 0; i < buttonValues.length; i++) {
if(buttonValues[i] === "a") {
//add attribute name and value to first two buttons
}
if(buttonValues[i] === "b"){
//add attribute name and value to first three buttons
}
};
return(
<div>
<button> One </button>
<button> Two </button>
<button> Three </button>
<button> Four </button>
</div>
)
}
const buttonValues = ["a", "b"]
const addingValuesToButtons = () => {
const buttons = [];
for (var i = 0; i < buttonValues.length; i++) {
if(buttonValues[i] === "a") {
buttons.push({attr: 'foo', name: 'bar'});
}
if(buttonValues[i] === "b"){
buttons.push({attr: 'baz', name: 'bar2'})
}
};
return(
<div>
{buttons.map(button => {
return <button attr={button.attr}>{button.name}</button>;
})}
</div>
)
}
It will go like this:
<button value={this.buttonValues[0] == 'a'?this.buttonValues[0]:null}> One </button>
another netter approach is :
const buttonValues = [{value:"a",name:"One"}, {value:"b",name:"two"}]
this.buttonValues.map(value => {<button value={value.value == 'a'? value.value:null}>{value.name}</button>}) ;
Related
So I have this problem, the goal of this code is that when I select 5 buttons from the table ( maximum number of clickable buttons) the 6th one that I will click, will make the first of five I clicked to be disabled, and then let the current one to be clicked. When the body is loaded, a table is created with buttons via js Example : I select the numbers : 1-2-3-4-5 and if I click the number 6 number 1 gets disabled or at least does not count between the 5 selected and gets the green class removed. I need to make this thing progressive so I will also need to track what is the "first" button I selected and I thought that the "best" way would be store the first one into an array of buttons.
That seems not to work because I get this error when the 5th button is clicked :
Uncaught TypeError: Cannot read properties of undefined (reading 'button')
at button.onclick
And that makes me think that when I access the array it actually can't store the buttons or either does not work. Am I trying to access the array wrongly? (firstButton = array_btn[previous].button) Assuming the input checks already work to verify that no more than 5 buttons are clicked how can I accomplish this goal? Thank you for the help in advance :) I apologize if some part of the code is still in Italian I did my best to set it as understandable as possible.
HTML :
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lotto</title>
<link rel="stylesheet" href="stile.css" />
<style>
#import url("https://fonts.googleapis.com/css2?family=Josefin+Sans&display=swap");
#import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
</style>
<script src="lotto.js"></script>
</head>
<body onload="createTable()">
<h1>Benvenuto all'Enalotto !</h1>
<p class="istruzioni">
Seleziona dalla tabella sottostante i numeri che vuoi giocare (MASSIMO 5
!)
</p>
<br />
<table id="tab-punt" class="tabella"></table>
<br /><br />
<p id="stampa" class="punt">Stai puntando i seguenti numeri :</p>
<button onclick="randomArray(); check();" class="bottone" id="btnvinto">
Scopri se hai vinto !
</button>
<p id="vincenti" class="vincenti"></p>
<p id="vinto" class="perso"></p>
<br /><br />
</body>
</html>
JavaScript :
let num = 1;
function createTable() {
let tabella = document.getElementById("tab-punt");
for (let i = 0; i < 10; i++) {
let nuovaRiga = tabella.insertRow(-1);
for (let j = 0; j < 9; j++) {
let nuovaCella = nuovaRiga.insertCell(j);
nuovaCella.appendChild(createButton(num));
num += 1;
}
}
}
//Creating arrays to store user input
const input = new Array(5);
var click_counter = 0;
var stringa_out = "";
var i = 0;
let lastButton;
let array_btn = [];
let previous;
//Function to create every single button
function createButton(index) {
let button = document.createElement("BUTTON");
button.classList.add("bot-tab");
//All buttons will share this class
button.classList.add("click");
var text = document.createTextNode(index);
button.appendChild(text);
button.onclick = function () {
let firstButton;
let currentButton;
currentButton = this;
array_btn.push({ currentButton });
input[i] = index;
i += 1;
button.classList.add("verde");
click_counter += 1;
if (click_counter === 5) {
firstButton = array_btn[previous].button;
firstButton.disabled = true;
//lastButton = button;
firstButton.classList.remove("verde");
click_counter -= 1;
previous+=1;
}
};
return button;
}
The below code should fix you issue, if it does not, let me know your end goal, since the way you are going about this is complex, it could be way more simple.
Let me know the goal, I would be able to give you a more simply code to achieve it.
Notes:
Only the code from 'let lastButton; onwards is included
See the comment lines starting with // <- for explanation
let lastButton;
let array_btn = [];
let previous = 0; // <- This should be initialised
//Function to create every single button
function createButton(index) {
let button = document.createElement("BUTTON");
button.classList.add("bot-tab");
//All buttons will share this class
button.classList.add("click");
var text = document.createTextNode(index);
button.appendChild(text);
button.onclick = function () {
let firstButton;
let currentButton;
currentButton = this;
array_btn.push({ button: currentButton }); // <- you need to assign button property as it is accessed later on
input[i] = index;
i += 1;
button.classList.add("verde");
click_counter += 1;
if (click_counter === 5) {
console.log(array_btn[previous]);
firstButton = array_btn[previous].button; // <- 'button' property accessed here
firstButton.disabled = true;
//lastButton = button;
firstButton.classList.remove("verde");
click_counter -= 1;
previous+=1;
}
};
return button;
}
You don't need any previous, lastButton etc variables, just a smarter way to add/remove HTMLButtonElements from your array of currently active (selected) buttons. Here's a possible solution that uses the simpler CSS Grid instead of a Table:
// DOM utility functions:
const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Enalotto game:
const elGrid = el("#buttons");
// Array to store the active HTMLButtonElements
const playedButtons = [];
const playButton = (elBtn) => {
const idx = playedButtons.indexOf(elBtn);
// Remove button if already in array
if (idx > -1) {
playedButtons.splice(idx, 1);
elBtn.classList.remove("is-active");
return; // Exit function here.
}
// Remove first clicked
if (playedButtons.length === 5) {
const elBtnFirst = playedButtons.shift();
elBtnFirst.classList.remove("is-active");
}
// Add to array
playedButtons.push(elBtn);
elBtn.classList.add("is-active");
};
const newButton = (index) => elNew("button", {
type: "button",
textContent: index + 1,
className: "bot-tab click",
onclick() {
playButton(this);
}
});
const createButtons = () => {
const buttons = [...Array(90).keys()].map(newButton);
elGrid.append(...buttons);
};
// Init game:
createButtons();
#buttons {
display: grid;
grid-template-columns: repeat(9, 2rem);
grid-template-rows: repeat(10, 2rem);
}
.is-active {
background: green;
}
<div id="buttons"></div>
With the above code, when you want to get an array of the values, lotto numbers the user selected all you need is:
const userNumbers = playedButtons.map(elBtn => elBtn.textContent);
// which gives i.e:
// ["12", "45", "2", "5", "86"]
In this React Javascript Calculator, decimal points are able to be added to numbers, but only after a complete browser refresh, and not after clicking the clear button which triggers the clear() function. How can state be completely and totally reset in the clear() function so that state becomes as if a browser refresh had been done. Any help would be greatly appreciated.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';
const initState = {
text: '0',
operators:['+']
}
class JavascriptCalculator extends React.Component {
constructor(props) {
super(props);
this.state = initState;
this.display = this.display.bind(this);
this.clear = this.clear.bind(this);
this.calculate = this.calculate.bind(this);
}
display(text){
// if display is zero, remove the leading zero from the text.
if(this.state.text == 0){
this.state.text = '';
}
let regex = /[*/+-]/;
// if text is not an operator
if (!regex.test(text)){
let displayed = this.state.text
// start by adding text
displayed += text;
// disallow multiple decimal points in a number
// if attempt at more than one decimal point remove last one.
let array = displayed.split('');
let count = 0;
for (let i = 0; i < array.length; i++){
if (array[i] === '.'){
count++;
}
}
// one decimal point is allowed per operator.
// thus to allow the first decimal point,
// this.state.operators must be initialized
// to length of 1.
if(count > this.state.operators.length){
array.pop();
}
displayed = array.join('');
this.setState({ text: displayed});
}
// if text is an operator
if (regex.test(text)){
// add the text to the array
// so that repeated decimal points are prevented
let array = this.state.operators;
array.push(text);
this.setState({ operators: array});
let displayed = this.state.text
displayed += text;
this.setState({ text: displayed});
}
// if text is equals sign, run the calculate function.
if (text === '='){
let displayed = this.state.text.split('');
displayed.push('=');
console.log(displayed);
this.calculate(displayed);
}
}
calculate(displayed){
let regex = /[*/+-]/;
let text = '';
let length = displayed.length;
let operators = [];
//console.log(this.state.array);
// capture numbers longer than one digit by adding them to a string
// and adding a comma in place of the operators, so the string
// can be split into an array at the operators.
for (let i = 0; i < length; i++){
// put numbers into a string
if (displayed[i].match(/[\d.]/)) {
text+=displayed[i];
}
// add commas to string in place of operators
if (displayed[i].match(regex)){
text+=',';
// add operators to their own array
operators.push(displayed[i]);
}
if (displayed[i] === '='){
break;
}
}
//console.log(operators);
// create the numbers array
let numbers = text.split(',');
//console.log(numbers);
// initialize answer with first number
let answer = numbers[0];
let func = undefined;
// Start with second number
for (let i = 1; i < numbers.length; i++){
func = returnFunc(operators.shift());
answer = func(answer, numbers[i]);
this.setState({text: answer})
}
function returnFunc(val) {
switch (val) {
case '+':
return function sum(a,b) { return Number(a)+Number(b)};
case '-':
return function subtract(a,b) { return Number(a)-Number(b)};
case '*':
return function multiply(a,b) { return Number(a)*Number(b)};
case '/':
return function divide(a,b) { return Number(a)/Number(b)};
default:
throw new Error("Called with unknown operator " + val);
}
}
}
clear(){
this.setState({text:'0', operators:'+'});
}
render() {
return (
<div id="javascript-calculator">
<h1 id="title">Javascript Calculator</h1>
<div id="display">{this.state.text}</div>
<hr/>
<div>
<button id="clear" onClick={e => this.clear()}> clear </button>
<button id="equals" onClick={e => this.display("=")}> = </button>
<button id="zero" onClick={e => this.display("0")}> 0 </button>
<button id="one" onClick={e => this.display("1")}> 1 </button>
<button id="two" onClick={e => this.display("2")}> 2 </button>
<button id="three" onClick={e => this.display("3")}> 3 </button>
<button id="four" onClick={e => this.display("4")}> 4 </button>
<button id="five" onClick={e => this.display("5")}> 5 </button>
<button id="six" onClick={e => this.display("6")}> 6 </button>
<button id="seven" onClick={e => this.display("7")}> 7 </button>
<button id="eight" onClick={e => this.display("8")}> 8 </button>
<button id="nine" onClick={e => this.display("9")}> 9 </button>
<button id="add" onClick={e => this.display("+")}> + </button>
<button id="subtract" onClick={e => this.display("-")}> - </button>
<button id="multiply" onClick={e => this.display("*")}> * </button>
<button id="divide" onClick={e => this.display("/")}> / </button>
<button id="decimal" onClick={e => this.display(".")}> . </button>
</div>
</div>
);
}
}
ReactDOM.render(<JavascriptCalculator />, document.getElementById("app"));
index.js
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Javascript Calculator</title>
<style>
</style>
</head>
<body>
<main>
<div id="app"></app>
</main>
</body>
</html>
Create a variable containing the initial state, then use it to replace the current state when you want to clear, like the below example:
const initState = {
text: '0',
array: [],
operators:['+']
}
...
constructor(props) {
super(props);
this.state = initState;
this.display = this.display.bind(this);
this.clear = this.clear.bind(this);
this.calculate = this.calculate.bind(this);
}
...
clear(){
this.setState(initState);
}
In this React Javascript Calculator this.setState({ array: displayed}); is supposed to update the array in state, but it doesn't. Is there a way to force it? Any help would be greatly appreciated.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';
class JavascriptCalculator extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 0,
array: [],
operators:['+']
}
this.display = this.display.bind(this);
this.clear = this.clear.bind(this);
this.calculate = this.calculate.bind(this);
}
display(text){
// if display is zero, remove the leading zero from the text.
if(this.state.text == 0){
this.state.text = ''
}
let regex = /[*/+-]/;
// if text is not an operator
if (!regex.test(text)){
let displayed = this.state.text
// disallow consecutive decimal points
if (text == '.' && displayed.slice(-1) == '.'){
return;
}
// start by adding text
displayed = this.state.text += text;
// disallow multiple decimal points in a number
// if attempt at more than one decimal point remove last one.
let array = displayed.split('');
let count = 0;
for (let i = 0; i < array.length; i++){
if (array[i] == '.'){
count++;
}
}
// one decimal point is allowed per operator.
// thus to allow the first decimal point,
// this.state.operators must be initialized
// to length of 1.
if(count > this.state.operators.length){
array.pop();
}
displayed = array.join('');
this.setState({ text: displayed});
}
// if text is an operator
if (regex.test(text)){
// add the text to the array
// so that repeated decimal points are prevented
let array = this.state.operators;
array.push(text);
this.setState({ operators: array});
// add the text to the text
let displayed = this.state.text += text;
this.setState({ text: displayed});
}
// if text ends in equals sign, run the calculate function.
if (text == '='){
let displayed = this.state.text.split('');
console.log(displayed);
this.setState({ array: displayed});
//this.state.array = displayed;
this.calculate();
}
}
calculate(){
let regex = /[*/+-]/;
let text = '';
let length = this.state.array.length;
let operators = [];
//console.log(this.state.array);
// capture numbers longer than one digit by adding them to a string
// and adding a comma in place of the operators, so the string
// can be split into an array at the operators.
for (let i = 0; i < length; i++){
// put numbers into a string
if (this.state.array[i].match(/[\d.]/)) {
text+=this.state.array[i];
}
// add commas to string in place of operators
if (this.state.array[i].match(regex)){
text+=',';
// add operators to their own array
operators.push(this.state.array[i]);
}
if (this.state.array[i] == '='){
break;
}
}
//console.log(operators);
// create the numbers array
let numbers = text.split(',');
//console.log(numbers);
// initialize answer with first number
let answer = numbers[0];
let func = undefined;
// Start with second number
for (let i = 1; i < numbers.length; i++){
func = returnFunc(operators.shift());
console.log(func);
answer = func(answer, numbers[i]);
}
this.display(answer);
function returnFunc(val) {
switch (val) {
case '+':
return function sum(a,b) { return Number(a)+Number(b)};
case '-':
return function subtract(a,b) { return Number(a)-Number(b)};
case '*':
return function multiply(a,b) { return Number(a)*Number(b)};
case '/':
return function divide(a,b) { return Number(a)/Number(b)};
default:
throw new Error("Called with unknown operator " + val);
}
}
}
clear(id){
this.setState({ text: id });
this.setState({ array: [] });
this.setState({ operators: [] });
}
render() {
return (
<div id="javascript-calculator">
<h1 id="title">Javascript Calculator</h1>
<div id="display">{this.state.text}</div>
<hr/>
<div>
<button id="clear" onClick={e => this.clear("0")}> clear </button>
<button id="equals" onClick={e => this.display("=")}> = </button>
<button id="zero" onClick={e => this.display("0")}> 0 </button>
<button id="one" onClick={e => this.display("1")}> 1 </button>
<button id="two" onClick={e => this.display("2")}> 2 </button>
<button id="three" onClick={e => this.display("3")}> 3 </button>
<button id="four" onClick={e => this.display("4")}> 4 </button>
<button id="five" onClick={e => this.display("5")}> 5 </button>
<button id="six" onClick={e => this.display("6")}> 6 </button>
<button id="seven" onClick={e => this.display("7")}> 7 </button>
<button id="eight" onClick={e => this.display("8")}> 8 </button>
<button id="nine" onClick={e => this.display("9")}> 9 </button>
<button id="add" onClick={e => this.display("+")}> + </button>
<button id="subtract" onClick={e => this.display("-")}> - </button>
<button id="multiply" onClick={e => this.display("*")}> * </button>
<button id="divide" onClick={e => this.display("/")}> / </button>
<button id="decimal" onClick={e => this.display(".")}> . </button>
</div>
</div>
);
}
}
ReactDOM.render(<JavascriptCalculator />, document.getElementById("app"));
index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Javascript Calculator</title>
<style>
</style>
</head>
<body>
<main>
<div id="app"></app>
</main>
</body>
</html>
setState is async. It won't work how you're using it. In your case, you should just pass the displayed array to the calculate function.
I used to make bunch of buttons through for-looping.
title[] has a lot of values.
export const renderButtons1 = (numOfBtns,title,navigate) => {
const views1 = [];
for ( var i = 0; i < numOfBtns; i++) {
views1.push(
<Button
key={i}
title = {title[i]}
onPress={() => navigate('List', {
Title : title[i]
})}
color="#841584"
/>);
}
return views1;
}
in EventListscreen, Title: title[i] does not work, i value is not recognized
the one I want to ask is when I click first button, index 0 will be retrieved.
I thought I can use button key, but it is not fixed value - when I click first button at first and at second time, it is different..
I found the way,
you guys need to make the function for making buttons
so it looks like this
export const makingbutton = (i,ttl,navigate) => {
return <Button
key={i}
title = {ttl[i]}
onPress={() => navigate('List', {
Title : title[i]
})}
color="#841584"
/>
}
export const renderButtons1 = (numOfBtns,title,navigate) => {
const views1 = [];
for ( var i = 0; i < numOfBtns; i++) {
views1.push(
makingbutton(i,title,navigate)
);
}
return views1;
}
I am using a foreach loop in php to load data from a mysql table. I'm using the data ID's loaded from the data base and applying it to the button values.
The buttons come in two colors, green and white. The buttons represent likes for liking comments or posts.
The total existing number of likes starts at 6 (div id="total")
white buttons
If button 1 has color of white and you click it, total likes (6) will increase by 1. If you click button 1 again, total likes (7) will decrease by 1.
If button 1, button 2, and button three are clicked, total likes (6) increases by 3 ( 1 for each button). If button 1, button 2 and button 3 are clicked again, the total likes (9) will decrease by 3.
The Puzzle
Green buttons
How do I make it so, When a green button is clicked, the total (6) decrease by 1, and if the button is clicked again, it should increase by 1. Unlike white buttons.
If Green button 3, 5 and 6 are clicked, the total (6) should decease by 3. if the same buttons are clicked again, total (6) increases by 3.
Here is my code
var colorcode = "rgb(116, 204, 49)";
var buttonid = str;
var elem = document.getElementById(buttonid);
var theCSSprop = window.getComputedStyle(elem, null).getPropertyValue("background-color");
var initialtotal = parseInt(document.getElementById("total").innerHTML, 10);
var likes = new Array();
function showUser(str) {
////// 1st condition /////
if (theCSSprop == colorcode) {
if (likes[value] == 0 || !likes[value]) {
likes[value] = 1;
} else {
likes[value] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum--
}
}
}
////// 2nd condition /////
else {
if (likes[str] == 0 || !likes[str]) {
likes[str] = 1;
} else {
likes[str] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum++
}
}
}
var tot = initialtotal + sum;
document.getElementById("total").innerHTML = tot;
}
<div id="total" style="width:100px;padding:50px 0px; background-color:whitesmoke;text-align:center;">6 </div>
<!---------------------------------------------------------------------------------------------------------------------->
<button id="5" value="5" onclick="showUser(this.value)">LIKE </button>
<button id="346" value="346" onclick="showUser(this.value)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="128" value="128" onclick="showUser(this.value)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="687" value="687" onclick="showUser(this.value)">LIKE </button>
<button id="183" value="183" onclick="showUser(this.value)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="555" value="555" onclick="showUser(this.value)">LIKE </button>
<!---------------------------------------------------------------------------------------------------------------------->
Instead of passing this.value to showUser(), just pass this. That way, the function can get the value and the style directly, without having to call getElementById() (you're not passing the ID). Then you need to set theCSSprop inside the function, so it's the property of the current button.
To make green buttons alternate direction from increment to decrement, you need a global variable that remembers what it did the last time the function was called.
Also, you don't need to write if(likes[str] == 0 || !likes[str]), since 0 is faley. Just write if(!likes[str]).
var colorcode = "rgb(116, 204, 49)";
var likes = new Array();
var greenIncr = -1;
function showUser(elem) {
var initialtotal = parseInt(document.getElementById("total").innerHTML, 10);
////// 1st condition /////
var str = elem.value;
var theCSSprop = window.getComputedStyle(elem, null).getPropertyValue("background-color");
if (theCSSprop == colorcode) {
if (!likes[str]) {
likes[str] = 1;
} else {
likes[str] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum += greenIncr;
}
}
greenIncr = -greenIncr; // revese the direction of green button
}
////// 2nd condition /////
else {
if (!likes[str]) {
likes[str] = 1;
} else {
likes[str] = 0;
}
var sum = 0;
for (i = 0; i < likes.length; i++) {
if (likes[i] == 1) {
sum++
}
}
}
var tot = initialtotal + sum;
document.getElementById("total").innerHTML = tot;
}
<div id="total" style="width:100px;padding:50px 0px; background-color:whitesmoke;text-align:center;">6 </div>
<!---------------------------------------------------------------------------------------------------------------------->
<button id="5" value="5" onclick="showUser(this)">LIKE </button>
<button id="346" value="346" onclick="showUser(this)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="128" value="128" onclick="showUser(this)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="687" value="687" onclick="showUser(this)">LIKE </button>
<button id="183" value="183" onclick="showUser(this)" style="background-color:rgb(116, 204, 49);">LIKE </button>
<button id="555" value="555" onclick="showUser(this)">LIKE </button>
<!---------------------------------------------------------------------------------------------------------------------->
First naive implementation can look like this
class Counter {
constructor(initial) {
this.initial = initial
this.white = [false, false, false]
this.green = [false, false, false]
}
changeGreen(index) {
this.green[index] = !this.green[index]
}
changeWhite(index) {
this.white[index] = !this.white[index]
}
get total() {
return this.initial + this.white.reduce((total, current) => total + current, 0) + this.green.reduce((total, current) => total - current, 0)
}
}
let counter = new Counter(6)
const render = counter => {
document.querySelector('#total').innerHTML = counter.total
}
render(counter)
;['#first', '#second', '#third'].map((selector, index) => {
document.querySelector(selector).addEventListener('click', e => {
e.target.classList.toggle('pressed')
counter.changeWhite(index)
render(counter)
})
})
;['#fourth', '#fifth', '#sixth'].map((selector, index) => {
document.querySelector(selector).addEventListener('click', e => {
e.target.classList.toggle('pressed')
counter.changeGreen(index)
render(counter)
})
})
.green {
background: #00aa00
}
.pressed {
border-style: inset
}
<div id="total">0</div>
<p>
<button id="first">First</button>
<button id="second">Second</button>
<button id="third">Third</button>
<button id="fourth" class="green">Fourth</button>
<button id="fifth" class="green">Fifth</button>
<button id="sixth" class="green">Sixth</button>
</p>
But after all I've finished with something like
class Counter {
constructor(initial, strategy) {
this.initial = initial;
this.elements = [];
this.strategy = typeof strategy === 'function' ? strategy : () => {}
}
addElement(content, type, next) {
const element = {
content: content,
type: type,
state: false
};
this.elements.push(element);
return next(element, this.elements.length - 1);
}
toggleElementState(index) {
this.elements[index].state = !this.elements[index].state
}
get total() {
return this.strategy(this.initial, this.elements)
}
}
const initialize = () => {
Counter.WHITE = Symbol('white');
Counter.GREEN = Symbol('green');
const counter = new Counter(6, (initial, buttons) => {
return initial +
buttons.filter(button => button.type === Counter.WHITE).reduce((total, current) => total + Number(current.state), 0) +
buttons.filter(button => button.type === Counter.GREEN).reduce((total, current) => total - Number(current.state), 0)
});
const render = counter => {
document.querySelector('#total').innerHTML = counter.total
};
const createButton = (element, index) => {
const button = document.createElement('button');
button.setAttribute('data-id', index);
button.classList.add(element.type === Counter.GREEN ? 'green' : 'none');
button.textContent = element.content;
document.querySelector('#buttons').appendChild(button)
};
const addButton = (type, ...selectors) => {
selectors.forEach(selector => counter.addElement(selector, type, createButton));
};
render(counter);
addButton(Counter.WHITE, '#first', '#second', '#third');
addButton(Counter.GREEN, '#fourth', '#fifth', '#sixth');
addButton(Counter.WHITE, '#first', '#second', '#third');
document.querySelector('#buttons').addEventListener('click', function(e) {
e.target.classList.toggle('pressed');
counter.toggleElementState(parseInt(e.target.dataset.id));
render(counter)
})
};
document.addEventListener('DOMContentLoaded', initialize);
.green {
background: #00aa00
}
.pressed {
border-style: inset
}
<div id="total">0</div>
<p id="buttons">
</p>