JS Make element disabled if === 1 - javascript

I want to disable the button when number is 1, using setAttribue
let element = document.createElement('div')
document.body.appendChild(element)
element.setAttribute('id', 'bet-size')
let text = document.createTextNode('1')
element.appendChild(text)
let click = document.createElement('input')
click.setAttribute('type', 'button')
click.setAttribute('id', 'decrease')
document.body.appendChild(click)
click.disabled = true
click.addEventListener('click', () => {
element.textContent = Number(element.textContent) - 1
if (element.textContent !== 1) {
click.setAttribute('disabled', true)
} else if (element.textContent > 1)
click.setAttribute('disabled', false)
})
Which way would be optimal to remove the attribute disabled when number is > 1?

Since disabled is either true or false, you can just check the value to see if its > 1 or not.
click.addEventListener('click', (e) => {
element.textContent = Number(element.textContent) - 1
e.target.setAttribute("disabled",(Number(element.textContent) - 1 > 1));
})

Related

Building a simple OPT forum

So I am trying to building a simple OPT forum which I have build but now I want to add reverse functionality for example when user press backspace input should focus on previous element.
const inputs = document.querySelectorAll('.input input')
inputs.forEach((e, i) => {
e.dataset.index = i;
e.addEventListener("input", () => {
if (e.value.length >= 1) {
if (e.dataset.index >= i && inputs.length - 1 > i) {
e.nextElementSibling.focus();
}
} else {
if (inputs.length - 1 > i || e.dataset.index < inputs.length) {
e.previousElementSibling.focus();
}
}
})
})
You would have to detect the press of the backspace key.
It looks like you want each input to take exactly one character. In that case I would suggest that you keep the current character selected, and to make arrow keys also move the focus.
Don't name the input element e, as e is usually used as name for the event object -- just to avoid confusion for someone reading your code.
Here is one way to do it:
const inputs = [...document.querySelectorAll('.input input')];
inputs.forEach((input, i) => {
const previous = () => inputs[i-1]?.focus?.();
const next = () => inputs[i+1]?.focus?.();
input.addEventListener("input", () => {
if (input.value.length > 1) input.value = input.value[0];
if (input.value.length) next();
});
input.addEventListener("keydown", (e) => {
if (e.key == "ArrowRight") next();
if (e.key == "ArrowLeft") previous();
});
input.addEventListener("keyup", (e) => {
if (e.key == "Backspace") {
previous();
e.preventDefault();
}
});
});
inputs[0].focus();
// Ensure that current input has its content selected
document.addEventListener("selectionchange", () => {
const input = document.activeElement;
if (inputs.includes(input)) input.setSelectionRange(0, 1);
});
.input input { width: 1em }
<div class="input">
<input><input><input><input><input>
</div>

Increment and decrement button with 'keydown' (ArrowUp and Down)

I need some help with a school assignment. I have two buttons, one for increment and one for decrement. I have four functions, where two of them is for clicking and two for pressing arrow keys. Clicking works fine, but to use arrowUp and ArrowDown i need to click and select the button with the mouse once for it to work. Can i add something to my two lower arrow key functions so that i dont need to click them once before i can start using arrow keys?
let element = document.querySelector('#value')
let buttonIncrease = document.querySelector('#increase')
element.textContent = '1'
let buttonDecrease = document.querySelector('#decrease')
buttonDecrease.disabled = true;
//Increment number by 1 on click
buttonIncrease.addEventListener('click', () => {
element.textContent = Number(element.textContent) + 1
if (element.textContent > 1) {
buttonDecrease.disabled = false;
}
})
//Decrement number by 1 on click
buttonDecrease.addEventListener('click', () => {
element.textContent = Number(element.textContent) - 1
if (element.textContent < 2) {
buttonDecrease.disabled = true;
}
})
//Increment number by 1 on keydown
buttonIncrease.addEventListener('keydown', (up) => {
if (up.key === 'ArrowUp' ) {
element.textContent = Number(element.textContent) + 1
}
if (element.textContent > 1) {
buttonDecrease.disabled = false;
}
})
//Decrement number by 1 on keydown
buttonDecrease.addEventListener('keydown', (down) => {
document.getElementById('decrease')
if (down.key === 'ArrowDown') {
element.textContent = Number(element.textContent) - 1
}
if (element.textContent < 2) {
buttonDecrease.disabled = true;
}
})
you dont need to define muse click on increment and decrement buttons
but to use arrowUp and ArrowDown i need to click and select the button
with the mouse once for it to work.
you can detect whene arrowUp and arrowDown clicked by add event lisner directly to keyboard:
addEventListener("keydown", function (e) { // Do something }
To do what you require you can attach the keydown event handler to the window, so that no matter what element in the DOM has focus, so long as the event can bubble to the window element, the value will be changed.
Also note that you can combine the keydown event handlers in to one, and you can also make the code more succinct and DRY by extracting the repeated logic in to functions:
let buttonIncrease = document.querySelector('#increase');
let buttonDecrease = document.querySelector('#decrease');
let element = document.querySelector('#value');
buttonDecrease.disabled = true;
element.textContent = '1';
const setButtonState = () => buttonDecrease.disabled = parseInt(element.textContent, 10) <= 1;
const updateValue = increment => {
value.textContent = Math.max(1, Number(element.textContent) + increment);
setButtonState();
}
buttonIncrease.addEventListener('click', () => updateValue(1))
buttonDecrease.addEventListener('click', () => updateValue(-1))
window.document.addEventListener('keydown', e => {
e.preventDefault();
let value = Number(element.textContent);
let increment = e.key === 'ArrowUp' ? 1 : e.key === 'ArrowDown' ? -1 : 0;
updateValue(increment);
})
#value {
padding: 3px;
}
<button id="decrease">-</button>
<span id="value">1</span>
<button id="increase">+</button>

Display Correct Radio Button Value Not Working with Default Checked Option?

Problem: Default checked radio button value shows on app, but if I change the tip value, then unselect and reselect a checkbox, it goes back to the original checked radio button value instead of changing to the new tip value.
Basicaly, my default radio checked button value is set to $5. If I select a checkbox option, then I change the tip value to $2 then unselect a checkbox, then reselect a checkbox, it will show the tip value as $5 instead of the new option $2
Here's my codepen. I added instructions on the codepen so you can see my problem
https://codepen.io/jaysomo10/pen/dydaKwZ
Here's my JS
window.menuItems = 0;
window.tips = 0;
const foodTotal = document.getElementById("price");
const tipTotal = document.getElementById("tip");
const orderTotal = document.getElementById("total");
let tipVal = document.querySelector(".tips:checked").value;
tipTotal.textContent = "$" + (tipVal / 100).toFixed(2);
document.addEventListener("click", ({ target }) => {
if (target.className === "food" && target.checked && tipVal) {
window.menuItems += parseInt(target.value);
window.tips = tipVal;
} else if (target.className === "food" && !target.checked) {
window.menuItems -= parseInt(target.value);
} else if (target.className === "tips" && target.checked) {
window.tips = parseInt(target.value);
} else {
return;
}
foodTotal.textContent = `$${(window.menuItems / 100).toFixed(2)}`;
tipTotal.textContent = `$${(window.tips / 100).toFixed(2)}`;
orderTotal.textContent = `$${(
(Number(window.menuItems) + Number(window.tips)) /
100
).toFixed(2)}`;
});
I can't seem to convert the logic to make the tip value to change after I unselect & re select a checkbox option.
tipVal is defined outside the click event. So it has always the value at the sart. You have to changhe it also inside the event
window.menuItems = 0;
window.tips = 0;
const foodTotal = document.getElementById("price");
const tipTotal = document.getElementById("tip");
const orderTotal = document.getElementById("total");
let tipVal = document.querySelector(".tips:checked").value;
tipTotal.textContent = "$" + (tipVal / 100).toFixed(2);
document.addEventListener("click", ({ target }) => {
tipVal = document.querySelector(".tips:checked").value;
if (target.className === "food" && target.checked && tipVal) {
window.menuItems += parseInt(target.value);
window.tips = tipVal;
} else if (target.className === "food" && !target.checked) {
window.menuItems -= parseInt(target.value);
} else if (target.className === "tips" && target.checked) {
window.tips = parseInt(target.value);
} else {
return;
}
foodTotal.textContent = `$${(window.menuItems / 100).toFixed(2)}`;
tipTotal.textContent = `$${(window.tips / 100).toFixed(2)}`;
orderTotal.textContent = `$${(
(Number(window.menuItems) + Number(window.tips)) /
100
).toFixed(2)}`;
});
remove this from your first if statement
if (target.className === "food" && target.checked && tipVal) {
window.menuItems += parseInt(target.value);
//window.tips = tipVal; // remove this
}

Select Table Row in React

I'm trying to achieve selecting just only one row at a time in my React Material App. My problem now is that it is highlighting many rows. I only need to highlight/select one row at a time.
Pls check this codesandbox link
CLICK HERE
CODE
const [selected, setSelected] = React.useState([]);
const selectFood = (event, food) => {
const selectedIndex = selected.indexOf(food.name);
let newSelected = [];
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, food.name);
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1));
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1));
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(
selected.slice(0, selectedIndex),
selected.slice(selectedIndex + 1)
);
}
setSelected(newSelected);
};
const isSelected = row => selected.indexOf(row.name) !== -1;
If you want to just select a single row -
then this would work definitely ( no need of complex code which you have written )
const selectFood = (event, food) => {
let newSelected = [food.name];
setSelected(newSelected);
};
Working link - https://codesandbox.io/s/highlightselect-rows-react-material-8ejbc?file=/demo.js:1016-1123

Shorten javascript code teaser

I have five input fields. When you delete the content from, let say first, that first input field is populated with input field 2, and the input field 5 is then empty. Again, if you delete the content from the first input field, the content from second goes into the first, and now you have input field four and five empty. And I need that five input field to disappear, to have left only one empty input field. And then again if the third and fourth element are empty, forth should disappear, and so on till there is only first input field left. So, I solve this with hard coded values:
if ((document.getElementsByClassName('requestRightsTitle4')[0].value == '')
&& (document.getElementsByClassName('requestRightsEmail4')[0].value == ''))
{
displayInputField('none', 5);
}
if (
(document.getElementsByClassName('requestRightsTitle3')[0].value == '')
&& (document.getElementsByClassName('requestRightsEmail3')[0].value == '')
&& (document.getElementsByClassName('requestRightsTitle4')[0].value == '')
&& (document.getElementsByClassName('requestRightsEmail4')[0].value == '')
)
{
displayInputField('none', 4);
}
if (
(document.getElementsByClassName('requestRightsTitle2')[0].value == '')
&& (document.getElementsByClassName('requestRightsEmail2')[0].value == '')
&& (document.getElementsByClassName('requestRightsTitle3')[0].value == '')
&& (document.getElementsByClassName('requestRightsEmail3')[0].value == '')
&& (document.getElementsByClassName('requestRightsTitle4')[0].value == '')
&& (document.getElementsByClassName('requestRightsEmail4')[0].value == '')
)
{
displayInputField('none', 3);
}
And now I would like to shorten this code like a real programmer but I don't have the time (sending me to another project) or skills to do so. But I would really like to learn how would that be possible, something like:
for (let i = 0; i < 5; i++) {
if (document.getElementsByClassName('requestRightsTitle' + i)[0].value == ''
&& document.getElementsByClassName('requestRightsEmail' + i)[0].value == '')
displayInputField('none', (i+1));
}
You can set up a listener on all your input fields. If a field is emptied, shift all remaining values to the left and determine which fields need to be displayed (i.e. all fields that have a value and the first empty field).
Here's a complete standalone snippet:
const action = (inputs) => {
const listener = () => {
const values = inputs.map(input => input.value).filter(v => v);
inputs.forEach((input, i) => {
input.value = values[i] || '';
input.style.display = values[i] || !i || values[i - 1] ? '' : 'none';
});
};
inputs.forEach((input, i) => input.addEventListener('input', listener));
};
action([...document.querySelectorAll('input')]);
<input value="One">
<input value="Two">
<input value="Three">
<input value="Four">
<input value="Five">
Better to use querySelector when you only want to select the first element. I'd make an object with the value of each element, and then check the object values:
const valsAreEmpty = ...vals => vals.every(val => val === '');
const vals = [
'requestRightsEmail2',
'requestRightsEmail3',
'requestRightsEmail4',
'requestRightsTitle2',
'requestRightsTitle3',
'requestRightsTitle4',
].map(classStr => document.querySelector('.' + classStr).value);
if (valsAreEmpty(
vals.requestRightsTitle4,
vals.requestRightsEmail4
)) {
displayInputField('none', 5);
}
if (valsAreEmpty(
vals.requestRightsTitle3,
vals.requestRightsEmail3,
vals.requestRightsTitle4,
vals.requestRightsEmail4
)) {
displayInputField('none', 4);
}
// etc
If there are even more Email# and Title# elements, you might use a loop to create the vals instead.
Some remarks :
it looks like you are using html classes to identify single elements in your page
you can use html classes more generically :
<input class="requestRightsTitle" />
<input class="requestRightsEmail" />
<input class="requestRightsTitle" />
<input class="requestRightsEmail" />
<input class="requestRightsTitle" />
<input class="requestRightsEmail" />
<input class="requestRightsTitle" />
<input class="requestRightsEmail" />
On the javascript side : document.getElementsByClassName('requestRightsEmail') will give you a useful array :
let emailInputs = document.getElementsByClassName('requestRightsEmail');
emailInputs[0].value = ...
emailInputs[1].value = ...
emailInputs[2].value = ...
...
// note : this array will be 0-indexed.
// emailInputs[0] will match your 'requestRightsEmail1'
This will probably help you on the css side too.
then you can more easily build and scan arrays of values
e.g :
let titles = document.getElementsByClassName('requestRightsTitle')
.map( e => e.value )
let emails = document.getElementsByClassName('requestRightsEmail')
.map( e => e.value )
// as said above : '3' matches 'requestRights4'
if (titles[3] == '' && emails[3] == '') {
displayInputField('none', 5);
}
if ( titles[2] == '' && emails[2] == ''
&& titles[3] == '' && emails[3] == '') {
displayInputField('none', 4);
}
you can then more easily put this in a loop
a final note, on what your sample does, and how you can rewrite it :
if requestRightsEmail3 is not empty, you already know that all the tests which include requestRightsEmail3 will return false.
So another way to look at your loop is :
if i is not empty, stop here, otherwise, show those extra fields :
for (let i = 3; i >= 1; i--) { // <- decreasing loop
// if one field contains something, stop here :
if (emails[i] != '' || titles[i] != '') {
break;
}
// otherwise : call your displayInputFields
displayInputField('none', i);
}

Categories

Resources