Consider the following code (keyCode is used for backward compatibility):
/**
* Navigate through the items.
*
* #param {Event} event
* #return void
*/
navigate(event) {
if (event.keyCode === 38 || event.key === "ArrowUp") {
this.active = this.active + 1 > this.items.length ? 0 : this.active + 1;
}
if (event.keyCode === 40 || event.key === "ArrowDown") {
this.active = this.active - 1 < 0 ? this.items.length : this.active - 1;
}
}
If the above is not clear, what I am trying to do is the following:
When incrementing this.active, make sure it is not greater than the length of this.items, and if it is, return it to 0
When decrementing this.active, make sure it is not less than 0, and if it is, return it to the length of this.items
The above code works absolutely fine but I know that it can be done better and more efficiently. For instance, calling this.active -1 twice in inefficent.
Is there a way to gracefully achieve this using something along the lines of Math.min and Math.Max?
I'd use the modulo operator instead:
navigate(event) {
const { length } = items;
if (event.keyCode === 38 || event.key === "ArrowUp") {
this.active = (this.active + 1) % length;
} else if (event.keyCode === 40 || event.key === "ArrowDown") {
this.active = (this.active - 1 + length) % length;
}
}
Related
I am trying to write a function that must convert a decimal number to binary and vice versa.
The function receives two arguments:
number, either binary/decimal
conversion to perform
Works fine when I pass binaryDecimal(5, 2); (// prints 101) for decimal to binary conversation.
When I pass the arguments to the function to convert binary to decimal, it does not print anything.
const binarioDecimal = (number = 0, base = 0) => { // 0 by default if the user does not pass any value
if (number === 0 || base === 0) {
console.log(0);
} else if (typeof number === "number" && typeof base === "number") {
if (base === 2) {
let num = number;
let binary = (num % 2).toString();
for (; num > 1; ) {
num = parseInt(num / 2);
binary = (num % 2) + binary;
}
console.log(binary);
}
} else if (typeof number === "number" && typeof base === "number") {
//this is where i think the function fails
if (base === 10) {
var decimal = 0,
i = 0,
resto;
while (number !== 0) {
resto = number % 10;
number = Number.parseInt(number / 10);
decimal = decimal + resto * Math.pow(2, i);
++i;
}
console.log(decimal);
}
}
};
binarioDecimal(); // 0
binarioDecimal(23, 2); // 10111
binarioDecimal(101, 10); //does not print anything :(
What if you split the checks into two separate conditions?
const binarioDecimal = (number = 0, base = 0) => {
if (number === 0 || base === 0) {
console.log(0);
}
if (base === 2) {
var num = number;
var binary = (num % 2).toString();
for (; num > 1; ) {
num = parseInt(num / 2);
binary = (num % 2) + binary;
}
console.log(binary);
}
if (base === 10) {
var decimal = 0,
i = 0,
resto;
while (number !== 0) {
resto = number % 10;
number = Number.parseInt(number / 10);
decimal = decimal + resto * Math.pow(2, i);
++i;
}
console.log(decimal);
}
}
binarioDecimal(); // 0
binarioDecimal(23, 2); // 10111
binarioDecimal(101, 10); // 5
The second
else if (typeof number === "number" && typeof base === "number")
is never executed.
Maybe try something like:
else if (typeof number === "number" && typeof base === "number" && base === 2)
{
...
}
else if (typeof number === "number" && typeof base === "number" && base === 10)
{
...
}
if you see what I mean!
The problem appears to be in your outermost if() statement. You have the following:
if(number === 0 || base === 0) {
/* your code */
} else if(typeof number === "number" && typeof base === "number") {
if(base === 2) { /* your code */ }
} else if(typeof number === "number" && typeof base === "number") {
if(base === 10) { /* your code */ }
}
Using this, if you call binarioDecimal(101, 10);:
if(number === 0 || base === 0)
is false
else if(typeof number === "number" && typeof base === "number")
is true
then if(base === 2)
is false
It then exits the whole statement, assuming it has fulfilled its purpose, never reaching the third else if(...) because it's the same as the previous one.
Putting the if(base === 10) with the if(base === 2) statement should resolve the issue.
if(number === 0 || base === 0) {
/* your code */
} else if(typeof number === "number" && typeof base === "number") {
if(base === 2) {
/* your code */
} else if(base === 10) {
/* your code */
}
}
That should solve why your code is never reached when the base is 10. Alternatively, outside of doing so for a coding exercise, you may want to look at Number.prototype.toString(radix); and Number.parseInt(string, radix); to convert between number bases. Hopefully this information is useful!
I have a number field to which I need to apply certain conditions with pure JS or jQuery:
Max 30
Min -30
Only 2 digits after the point, example 2.25
So possible values are like this (2.00 / 2.25 / 2.50/ 2.75 / 3.00...)
I managed to do so unless for the last condition that should accept only values .00 or .25 or .50 or .75
Here is my code:
var t_myField = false;
var myField_min = -30;
var myField_max = 30;
$('#myField').focus(function ()
{
var $this = $(this)
t_myField = setInterval(
function ()
{
if (($this.val() < myField_min || $this.val() > myField_max) && $this.val().length != 0)
{
if ($this.val() < myField_min)
{
$this.val(myField_min)
}
if ($this.val() > myField_max)
{
$this.val(myField_max)
}
}
}, 50)
});
$('#myField').on("keyup", function (e)
{
// Replacer , by .
$(this).val($(this).val().replace(/,/g, '.'));
// Allow only float numeric values (positif & negatif)
var self = $(this);
self.val(self.val().replace(/[^0-9\.-]/g, ''));
if (e.which != 46 && e.which != 45 && e.which != 46 && !(e.which >= 48 && e.which <= 57))
{
e.preventDefault();
}
// Allow max 2 digits after decimals for certain fields
match = (/(\d{0,2})[^.]*((?:\.\d{0,2})?)/g).exec(this.value.replace(/[^\d.]/g, ''));
this.value = match[1] + match[2];
});
<input type="text" name="myField" id="myField" class="myField">
JSFIDDLE => https://jsfiddle.net/Cartha/vq65Lypj/5/
[EDIT]
Control should be on keyup. This is why I can't use html5 attributes like min/max/step...
You can make use of % operator like x % 0.25 == 0 ? true : false
let myField = document.getElementById('myField');
myField.addEventListener('keypress', onlyNumbers,{passive: false});
myField.addEventListener('change', checkInput);
function onlyNumbers(e) {
if (!isNumberKey(e)) {
e.preventDefault();
}
}
function isNumberKey(e) {
return (e.which <= 31 || (e.which >= 48 && e.which <= 57) || e.which === 45 || e.which === 46);
}
function checkInput(e) {
let x = parseFloat(e.target.value);
if (!isNaN(x)) {
if (x > 30) {
x = 30;
} else if (x < -30) {
x = -30;
} else if (x % 0.25 !== 0) {
x = Math.round(x / 0.25) * 0.25;
}
e.target.value = x.toFixed(2);
}
}
This will allow only numbers with 0.25 steps.
Digit-only algorithm has been improved to completely prevent other type of input to be displayed (your code shows the forbidden input and then erases it).
This is the basic idea, a lot of other improvements can be made. For example, to always show two decimals (EX. 2.00 instead of 2), make an animation, etc. Currently, the check is set to happen after focus ends.
NOTE: Little extra improvements made in last edit.
JS Fiddle (I don't know how to embed it to the answer)
I would recommend creating a web component here. I'll show you the basic setup for a customized built-in with a component that already works and does not involve fumbling with $(document).ready() or DOMContentLoaded:
class DecimalInput extends HTMLInputElement {
constructor() {
super();
this.addEventListener('input', (e) => {
const val = parseFloat(this.value),
min = parseFloat(this.min),
max = parseFloat(this.max),
step = parseFloat(this.step);
if (val%step !== 0) {
this.value = Math.round(val/step) * step
}
if (val > max) {
this.value = max
}
if (val < min) {
this.value = min
}
this.value = Number(this.value).toFixed(2, 10);
})
}
}
customElements.define('decimal-input', DecimalInput, { extends: 'input' })
<input type="number" is="decimal-input" min="-30" max="30" step="0.25" value="0" />
This component is already quite close to your requirements. Use it to do our own refinements based on this.
This probably has an easy solution, but I simply don't see it at the moment.
I have three if-clauses that ashould be activated based on the length of an array. The first two ones seem to work fine, but for some odd reason I can't activate the third one (arr.length === 3). Right before the if clauses I have tried an alert to test whether it gives the right length of the array and it does.
function calculateDistances() {
var arr = [];
arr.push(posM, posL, posR);
alert(arr[1])
for (var i = 0; i < arr.length; i++) {
if (!arr[i]) {
arr.splice(i,1)
}
}
alert(arr.length)
if (arr.length === 0 || 1) {
return true;
}
else if (arr.length === 2 ) {
var diameter = calculateDiameter(arr[0], arr[1])
if (diameter > minDistance) {
return false;
}
else {
return true;
}
}
else if (arr.length === 3) {
alert("hello")
var diameter1 = calculateDiameter(arr[0], arr[1]);
var diameter2 = calculateDiameter(arr[0], arr[2]);
var diameter3 = calculateDiameter(arr[1], arr[3]);
if (diameter1 && diameter2 && diameter3 < minDistance) {
return true
}
else{
return false
}
}
}
Nor can you activate the second.
There's a bug here: if (arr.length === 0 || 1) {
The 1 casts to true.
Perhaps you meant: if (arr.length === 0 || arr.length === 1) {
You need this:
if (arr.length === 0 || arr.length === 1) {
The way you put it, it is equal to
if ((arr.length === 0) || true) {
which is always true.
I think what you are looking for is below condition in the first if condition
if (arr.length === 0 || arr.length === 1) {
return true;
}
this checks whether the length of the array is 1 or it's 0. Your first if condition is always true as it has 1 which is true.
(arr.length === 0 || 1)
is always true.
You could usethis instead
if (arr.length <= 1)
{
return true;
}
I have a requirement wherein I can enter number not more than 100 (100 allowed). Additionally these number can have +, - sign at start and % at the end.
I have come up with the following function to validate. However, even after struggling a lot, I am unable to fix why I am not able to enter a % sign when I have already enter 2 digits.
Ex: after typing 10, I cant type % (Shift + 5)
My Function:
$scope.checkInputValidation = function(event, value) {
var key = event.keyCode;
var currentcharacter = String.fromCharCode(key);
if (key === 91 || key === 187 || key === 189 || (15 < key && key < 19) || (35 <= key && key <= 40)) {
return;
}
if (isNaN(currentcharacter) && ((currentcharacter !== "%") || (currentcharacter !== "+") || (currentcharacter !== "-") || (currentcharacter !== ""))) {
if ((key !== 46) && (key !== 8)) {
event.preventDefault();
return false;
}
}
var formattedValue;
if (value.indexOf('%') !== -1) {
formattedValue = value.replace('%', "");
} else {
formattedValue = value;
}
if (!isNaN(currentcharacter)) {
if (parseInt(formattedValue + currentcharacter) > 100 || parseInt(formattedValue + currentcharacter) < -100) {
event.preventDefault();
return false;
}
}
}
I would like to know the cause and how should I be able to enter %.
currentcharacter is never going to contain the % character. You have to check the keyCode for 5 (53) in combination with the event.shiftKey property.
if(key === 53 && event.shiftKey) {
.. % pressed ..
}
How can I make the following code more elegant and readable?
if (this.flag === 1) {
this.value -= 0.1;
}
if (this.value <= 0) {
this.flag = 0;
}
if (this.flag === 0) {
this.value += 0.1;
}
if (this.value >= 1) {
this.flag = 1;
}
Edit: Let's say, for simplicity's sake, I'm changing the opacity of an object, and I want it to fade in and out from 0 to 1 over and over inside some sort of loop. .value is the opacity, and .flag is to tell it when to switch directions.
You could simplify some if-else scenarios with shorthand notations like below.
this.flag = this.value <= 0 ? 0 : 1;
this.value = this.value + (this.flag === 1 ? -0.1 : 0.1);
However, your script, in its current form, uses exclusive if conditions that don't cover all possible values of flag and value with an else block. Depending on whether you care about that, my proposal above could break your code.
EDIT - based on OP updates
flag should be a boolean true/false.
this.flag = this.value > 0;
this.value += (this.flag ? -0.1 : 0.1);
EDIT 2 - based on comments
Why should this.flag be manipulated through the value of this.value? The flag should be controlled through other means such as a checkbox or something, so your opacity change script should really be just this:
this.value += (this.flag ? -0.1 : 0.1);
If you're trying to auto-toggle the flag when the opacity reaches 0 or 1, you can do this:
this.value += (this.flag ? -0.1 : 0.1);
if(this.value === 1 || this.value === 0) {
this.flag = !this.flag;
}
Please note that this answer has already drifted outside of the scope of the question, which was to have a more elegant approach to conditionals. You'd be better off asking a new SO question if you need to discuss any further.
Based on what you have right now I would do this :
if (this.flag === 1) {
this.value -= 0.1;
} else if (this.flag === 0) {
this.value += 0.1;
}
if (this.value <= 0) {
this.flag = 0;
} else if (this.value >= 1) {
this.flag = 1;
}
But can flag be a boolean value? If so you don't need to the the numerical value check. Also can this.value be anywhere between 0-1? Flag isn't set in this case. If possible I would refactor the code like this but it depends on the logic you are trying to implement
if (this.flag) {
this.value -= 0.1;
} else {
this.value += 0.1;
}
if (this.value <= 0) {
this.flag = 0;
} else {
this.flag = 1;
}
This changes the outcome a bit, but I think it is what you actually want:
if (this.flag === 1) {
this.value -= 0.1;
if (this.value <= 0)
this.flag = 0;
} else /* if (this.flag === 0) */ {
this.value += 0.1;
if (this.value >= 1)
this.flag = 1;
}
While it still might not be elegant, it's at least easy to understand, as you only have a cyclomatic complexity of 4 (instead of 16 as in your original code).
For an elegant solution, you'd change even more. Instead of using a "flag" for the direction, you could represent the direction itself by the amount of change:
this.value += this.dir;
if (this.value >= 1)
this.dir = -0.1;
else if (this.value <= 0)
this.dir = 0.1;
Or then again, maybe even
this.value += this.dir;
if (this.value <= 0 || this.value >= 1)
this.dir *= -1;