Calculating width of a element incorrectly - javascript

I'm trying to calculate the width of block, id="titleText" I am getting some luck, although it calculates incorrectly.
For example, when empty it still shows pixels (by default, it should be one), yet 18px remains in this example:
(using onkeydown)
(using onkeyup)
and...
Triggering my style logic before the number I specified, which is 585.
My HTML is:
<input type="text" autocomplete="off" id="serpTitle"
onkeydown="checkTitleValue()" class="form-control" />
<p class="d-block" id="titleText"></p>
and the Javascript
function checkTitleValue() {
var fontSize = 12;
var measureTitle = document.getElementById("titleText");
measureTitle.style.fontSize = fontSize;
var height = (measureTitle.clientHeight + 1) + "px";
var width = (measureTitle.clientWidth + 1) + "px"
var inputTitle = document.getElementById("serpTitle").value;
document.getElementById("titleText").innerText = inputTitle;
document.getElementById("titlePixels").innerText = width;
if (measureTitle.clientWidth + 1 > 585) {
document.getElementById("titlePixels").style.color = "red";
}
else if (measureTitle.clientWidth + 1 < 585)
{
document.getElementById("titlePixels").style.color = null;
}
}

Could you please try this code snippet. I don't get the point of this measureTitle.clientWidth + 1 or measureTitle.clientWidth + 1 < 585
const FONT_SIZE = 12;
const MAX_LENGTH = 585;
var serpTitle = document.getElementById('serpTitle');
var mesured = document.getElementById('measured');
var maxLength = document.getElementById('max-length');
var measureCont = document.getElementById('mesure-cont');
function init() {
measureCont.style.fontSize = FONT_SIZE;
maxLength.innerHTML = MAX_LENGTH + 'px';
updateMesure();
}
function updateMesure() {
measureCont.innerHTML = serpTitle.value;
mesured.innerHTML = measureCont.clientWidth;
}
function checkTitleValue() {
updateMesure();
if (measureCont.clientWidth > MAX_LENGTH) {
measured.style.color = 'red';
} else {
measured.style.color = null;
}
}
init();
<div>
<input type="text" autocomplete="off" id="serpTitle" onkeyup="checkTitleValue()"
class="form-control" />
<span id="measured"></span>/<span id="max-length"></span>
</div>
<div>
<span style="display: inline-block" id="mesure-cont">aaaaa</span>
</div>

You should probably try calling the function on keyup instead of keydown.
Since each keystroke is ACTUALLY executed in the input box at keyup: Meaning.. (after) the key has been "pressed".
So your HTML code probably should go like:
<input type="text" autocomplete="off" id="serpTitle"
onkeyup="checkTitleValue()" class="form-control" />
<p class="d-block" id="titleText"></p>

one of the issue, regarding changing color, is that you first updating color then calculating it. So swap
if (measureTitle.clientWidth > 585) {
document.getElementById("titlePixels").style.color = "red";
}
else if (measureTitle.clientWidth < 585)
{
document.getElementById("titlePixels").style.color = null;
}
document.getElementById("titleText").innerText = inputTitle;
document.getElementById("titlePixels").innerText = width;

Related

All buttons only affect one input instead of respective input

I am making a little project for my self. So basically its main function is to create a base counter for each game.
For example: If there are two players it should create three bases. (This is for the card game "smash up" if that helps you understand better.) But when the Buttons populate they all only effect the last input. I can not figure out how to make them effect their respective inputs.
The problem I am having is that every button I click only effects the last input.
<html>
<title> Base Maker </title>
<body>
<div>
<hl> Score Keeper </h1>
<hr>
<input type = "text" placeholder = "How many players?">
<button id = "enter" onclick = "baseMaker()">
Enter
</button>
</div>
<p></p>
</body>
</html>
var parent = document.querySelector("p");
var input = document.querySelector("input");
var enter = document.getElementById("enter");
function baseMaker()
{
for(var i = 0; i <= input.value; i++)
{
//base
var base = document.createElement("p");
base.textContent = "Base " + (i + 1) + ":";
//score
var score = document.createElement( "input");
score.setAttribute("id", "score" + i);
score.value = 20;
//upbutton
var upButton = document.createElement( "button");
upButton.textContent = "+";
upButton.setAttribute("id", "upButton" + i)
upButton.addEventListener('click', function() {
score.value++; });
//downbutton
var downButton = document.createElement( "button");
downButton.textContent = "-";
downButton.setAttribute("id", "downButton" + i)
downButton.addEventListener('click', function() {
score.value--; });
//populate data
parent.appendChild(base);
parent.appendChild(score);
parent.appendChild(upButton);
parent.appendChild(downButton);
}
input.value = "";
}
This is a common thing to run into especially when not using a framework in javascript.
I am not sure why this happens but when a function is defined directly in a loop, the closure for these created functions becomes whatever it is after the last iteration. I believe it is because the closure for each callback function is only "sealed up" (for lack of a better word) at the end of the loop-containing-function's execution which is after the last iteration. It's really beyond me, though.
There are some easy ways to avoid this behavior:
use bind to ensure a callback gets called with the correct input (used in solution at bottom)
create a function which creates a handler function for you and use that in the loop body
function createIncrementHandler(input, howMuch){
return () => input.valueAsNumber += howMuch;
}
/// then in your loop body:
downButton.addEventListener('click', createIncrementHandler(score, 1));
get the correct input by using the event parameter in the handler
downButton.addEventListener('click', (event) => event.target.valueAsNumber += 1);
make the entire body of the loop into a function, for example:
function createInputs(i) {
//base
var base = document.createElement("p");
base.textContent = "Base " + (i + 1) + ":";
//score
var score = document.createElement("input");
score.type = "number";
score.setAttribute("id", "score" + i);
score.value = 20;
//upbutton
var upButton = document.createElement( "button");
upButton.textContent = "+";
upButton.setAttribute("id", "upButton" + i)
upButton.addEventListener('click', function() {
score.value++; });
//downbutton
var downButton = document.createElement( "button");
downButton.textContent = "-";
downButton.setAttribute("id", "downButton" + i)
downButton.addEventListener('click', function() {
score.value--; });
//populate data
parent.appendChild(base);
parent.appendChild(score);
parent.appendChild(upButton);
parent.appendChild(downButton);
}
Here is a full example of one of the possible fixes.
<html>
<title> Base Maker </title>
<body>
<div>
<hl> Score Keeper </h1>
<hr>
<input type="text" placeholder="How many players?">
<button id="enter" onclick="baseMaker()">
Enter
</button>
</div>
<p></p>
<script>
var parent = document.querySelector("p");
var input = document.querySelector("input");
var enter = document.getElementById("enter");
function incrementInput(input, byHowMuch) {
input.valueAsNumber = input.valueAsNumber + byHowMuch;
}
function baseMaker() {
for (var i = 0; i <= input.value; i++) {
//base
var base = document.createElement("p");
base.textContent = "Base " + (i + 1) + ":";
//score
var score = document.createElement("input");
score.type = "number";
score.setAttribute("id", "score" + i);
score.value = 20;
//upbutton
var upButton = document.createElement("button");
upButton.textContent = "+";
upButton.setAttribute("id", "upButton" + i)
upButton.addEventListener('click', incrementInput.bind(null, score, 1));
//downbutton
var downButton = document.createElement("button");
downButton.textContent = "-";
downButton.setAttribute("id", "downButton" + i)
downButton.addEventListener('click', incrementInput.bind(null, score, -1));
//populate data
parent.appendChild(base);
parent.appendChild(score);
parent.appendChild(upButton);
parent.appendChild(downButton);
}
input.value = "";
}
</script>
</body>
</html>
I will do that this way :
const
AllBases = document.querySelector('#bases')
, bt_Start = document.querySelector('#game-go')
, bt_newGame = document.querySelector('#new-game')
, playerCount = document.querySelector("#play-start > input")
;
playerCount.value = ''
playerCount.focus()
playerCount.oninput = () =>
{
playerCount.value.trim()
bt_Start.disabled = (playerCount.value === '' || isNaN(playerCount.value))
playerCount.value = (bt_Start.disabled) ? ''
: (playerCount.valueAsNumber > playerCount.max) ? playerCount.max
: (playerCount.valueAsNumber < playerCount.min) ? playerCount.min
: playerCount.value
}
bt_newGame.onclick = () =>
{
playerCount.value = ''
playerCount.disabled = false
bt_Start.disabled = true
bt_newGame.disabled = true
AllBases.innerHTML = ''
playerCount.focus()
}
bt_Start.onclick = () =>
{
playerCount.disabled = true
bt_Start.disabled = true
bt_newGame.disabled = false
for(let i = 0; i <= playerCount.valueAsNumber; i++)
{
let base = document.createElement('p')
base.countValue = 20 // create a counter property on <p>
base.innerHTML = `Base ${i+1} : <span>${base.countValue}</span> <button>+</button> <button>−</button>\n`
AllBases.appendChild(base)
}
}
AllBases.onclick = ({target}) =>
{
if (!target.matches('button')) return // verify clicked element
let countElm = target.closest('p')
if (target.textContent==='+') countElm.countValue++
else countElm.countValue--
countElm.querySelector('span').textContent = countElm.countValue
}
#bases p span {
display : inline-block;
width : 6em;
border-bottom : 2px solid aqua;
padding-right : .2em;
text-align : right;
margin : 0 .3em;
}
#bases p button {
width : 2em;
margin : 0 .1em;
cursor : pointer;
}
<hr>
<hl> Score Keeper </h1>
<hr>
<div id="play-start" >
<input type="number" placeholder="How many players?" min="2" max="4">
<button id="game-go" disabled> Enter </button>
<button id="new-game" disabled> new </button>
</div>
<hr>
<div id="bases"></div>
If it helps, I can add more explanations

Coloring with a two color scale in HTML and JavaScript

I have an input element whose value is a number between 0 and 100. I am attempting to style the element via a two-color scale, taking its value as the input.
I am planning on making a simple gradient:
When the number is 100, the element's background color is green #00ff00
When the number is 0, it is red #ff0000
When the number is 50, it displays a yellow color #ffff00
The in-between values should be colored according to the scale.
I have tried using an if statement in JavaScript, but that fails to create a gradient, as there is a hard border between red, yellow, and green (sans gradient). See the code below:
var x = 0;
function color() {
x = document.getElementById("color").value;
console.log(x);
if (x > 50) {
document.getElementById('color').style.backgroundColor = "#00ff00";
}
else if (x == 50) {
document.getElementById('color').style.backgroundColor = "#ffff00";
}
else {
document.getElementById('color').style.backgroundColor = "#ff0000";
}
}
<button onclick="color();">Run</button>
<input type="number" id='color' value=50></input>
<!-- The input is not disabled for value debugging. -->
Is there concise way to perform this task?
const updateColor = (target) => {
const value = target.value;
//#00ff00 100
//#ffff00 50
//#ff0000 0
const R = Math.round((255 / 50) * (value < 50 ? 50 : 100 - value)).toString(16)
const G = Math.round((255 / 50) * (value > 50 ? 50 : value)).toString(16)
const twoDigit = (d) => ("0" + d).slice(-2);
const nextColor = '#' + twoDigit(R) + twoDigit(G) + '00';
target.style.background = nextColor
}
document.getElementById('color').addEventListener('change', (e) => updateColor(e.target));
document.addEventListener("DOMContentLoaded", function (event) {
updateColor(document.getElementById('color'))
});
<html>
<body>
<input type="number" id="color" min="0" max="100" value="0">
</body>
</html>
You can use Html Range input for this purpose and Use javascript for getting its value. Like:
<input id="myId" type="range" min="0" max="100">
Use Javascript to get its value by using its ID. Use a Javascript function. Either call it using a button or add onchange event.
You are just missing a style property...
just do this
document.getElementById("color").style.background = "Any Color";
or if you want to change text color then
document.getElementById("color").style.color = "Any Color";
Here I wrote full code for your problem:-
<input type="number" id="color" min="0" max="100" onkeyup="check()">
<script>
function check(){
c = document.getElementById("color");
x = c.value;
if(x==0)
c.style.background="Red";
else if(x==50)
c.style.background = "Yellow";
else
c.style.background = "Green";
}
</script>
I have found the optimal way to create a 2 color scale that uses vibrant, hexadecimal colors:
var colval = 0;
var R = 0;
var G = 0;
var B = 0;
function check() {
c = document.getElementById("color");
x = c.value;
if (x > 50) {
R = Math.round(-0.051 * x ** 2 + 2.55 * x + 255);
G = 255;
} else if (x < 50) {
R = 255;
G = Math.round(-0.051 * x ** 2 + 7.65 * x + 0);
} else {
R = 255;
G = 255;
}
B = 0;
colval = "#" + R.toString(16) + G.toString(16) + "00";
c.style.background = colval;
}
<html>
<body>
<input type="number" id="color" min="0" max="100" value="0" onkeyup="check()">
</body>
</html>

On mouse hover, display the corresponding sizes of bars, as mentioned in the input field

function draw() {
var nums = document.getElementById("number").value.split(",");
console.log(nums);
var w = 40;
var factor = 20;
var n_max = Math.max.apply(parseInt, nums);
var h_max = factor * n_max;
console.log("h max is " + h_max);
console.log("n max is " + n_max);
//var h_max = Math.max(h);
//var a = parseInt(nums);
//var create = document.getElementById("shape");
for (var i = 0; i <= nums.length; i++) {
//var x = parseInt(nums[i]);
//var final_width = w / x;
var x_cor = (i + 1) * w;
//var y_cor = i * w * 0.5;
var h = factor * nums[i];
console.log(x_cor);
console.log(h);
//console.log(h_max);
var change = document.getElementById("histContainer");
//change.className = 'myClass';
var bar = document.createElement("div");
bar.className = 'myClass';
//var c_change = document.createElement("div2");
//change.appendChild(c_change);
change.appendChild(bar);
console.log(change);
//change.style.x.value = x_cor;
//change.style.y.value = y_cor;
bar.style.position = "absolute";
bar.style.top = (h_max - h) + "px";
//bar.style.transform = "rotate(-1deg)"
bar.style.left = i * w * 1 + "px";
bar.style.backgroundColor = "rgb(1,211,97)";
bar.style.opacity = "0.6";
bar.style.width = w + "px";
bar.style.height = h + "px";
//var color1 = document.getElementById("histContainer");
//var bar_color = document.createElement("div");
//color1.appendChild(change);
//bar.style.color = "rgba(1,211,97,0.6)";
}
}
function color() {
//draw();
var change1 = document.getElementsByClassName('myClass');
for (var i = 0; i < change1.length; i++) {
change1[i].style.backgroundColor = "rgb(255,0,27)";
console.log("Change1 = " + change1[i]);
}
// var bar1 = document.createElement("div2");
// change1.appendChild(bar1);
// console.log(change1);
//change1.style.backgroundColor = "rgb(1,,254,16)";
}
$(document).ready(function() {
$(document).on("mouseover", ".myClass", function() {
//var number = this.nums;
//$(this.nums).text($(this.nums).index());
//$(".myClass").append(nums);
var shade = $(this).css("opacity");
$(this).css("opacity", "1.0");
$(document).on("mouseout", ".myClass", function() {
$(this).css("opacity", shade);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
Number:<input type="text" id="number" /><br>
<input type="button" id="button1" value="Draw" onClick="draw()" /><br>
<input type="button" id="button2" value="Change Color" onClick="color()" /><br>
<div id="histContainer" style="position: relative;"> </div>
<!-- <label for="mouseover" id="label1">Bar Value</label><br>
<input type="text" name="mouseover" id="text2" value="0"/><br> -->
<!-- <input type="button" id="color_change" style="float: right;" value="Change Color" /> -->
My Question is- I have entered some numbers as Input, and corresponding histogram is made according to the input values. Now, I have created mouseover() on each bar, and WANT to display their proportionate sizes, as given in input.
Can you provide me some help? Only thing which i figured out was- I have to call my draw function in the jQuery mouseover.
REFER TO the draw() and jQuery function(last)
I have figured out the answer. It is required that the nums array has to be re-declared again.
Solution Achieved
$(document).ready(function() {
$(document).on("mouseover",".myClass", function(){
//var numbers = $("#number").serialize();
//var number = this.nums;
var nums = document.getElementById("number").value.split(",");
$(this).text(nums[$(this).index()]);
//$(".myClass").append(nums);
var shade = $(this).css("opacity");
$(this).css("opacity", "1.0");
$(document).on("mouseout",".myClass", function() {
$(this).css("opacity", shade);
});
});
});

Why does my value keep returning as "NaN"?

Here is the link to the jsbin.
I was almost finished with my project (I thought I was) and then I tested it out. It is supposed to add buttons with the chosen title of the task and the number of points it awards. Every time the button is clicked the points would be added on to the "Points" section and every 500 points my "Level" would increase.
Upon finishing it, it worked. Then I went to clear the localStorage since that's what I used to save the information, but I wanted to start over. When I did that, the 'Points' section, or 'results' value, keeps returning as "NaN". The code is exactly the same as it was when it worked. Can someone please tell me how to fix this problem, thank you in advance.
Here is the code. (Used bootstrap for CSS)
HTML
<center>
<br>
<h2> Add task </h2>
<div class='well' style='width:500px' id="addc">
<div id="addc">
<input class='form-control' style='width:450px' id="btnName" type="text" placeholder="New Task" /><br>
<input class='form-control' style='width:450px' id="btnPoints" type="text" placeholder="Points" /><br>
<button id="addBtn">Add</button>
</div> </div>
<div class='well' style='width:230px' id="container">
</div>
<hr style="width:400px;">
<h3>Points </h3>
<div id="result">0</div>
</div>
<hr style="width:400px;">
<div style="width:400px;">
<h3>Level
<p id='lvl'>0</p>
</div>
<hr style="width:400px;">
</center>
JavaScript
var res = document.getElementById('result');
res.innerText = localStorage.getItem('myResult');
var level = document.getElementById('lvl');
level.textContent = localStorage.getItem('myLevel');
var btns = document.querySelectorAll('.btn');
for(var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function() {
addToResult(this.getAttribute('data-points'));
this.parentNode.removeChild(this.nextElementSibling);
this.parentNode.removeChild(this);
});
}
var addBtn = document.getElementById('addBtn');
addBtn.className = "btn btn-default";
addBtn.addEventListener('click', function() {
var container = document.getElementById('container');
var btnName = document.getElementById('btnName').value;
var btnPoints = parseInt(document.getElementById('btnPoints').value);
if(!btnName)
btnName = "Button ?";
if(!btnPoints)
btnPoints = 50;
var newBtn = document.createElement('button');
var newPnt = document.createElement('span');
newBtn.className = 'btn btn-danger';
newBtn.innerText = btnName;
newBtn.setAttribute('data-points', btnPoints);
newBtn.addEventListener('click', function() {
addToResult(this.getAttribute('data-points'));
this.parentNode.removeChild(this.nextElementSibling);
this.parentNode.removeChild(this);
});
newPnt.className = 'label';
newPnt.innerText = "+" + btnPoints;
container.appendChild(newBtn);
container.appendChild(newPnt);
});
function addToResult(pts) {
var result = document.getElementById('result');
result.innerText = parseInt(result.innerText) + parseInt(pts);
var lvl = 0;
var a = 100;
while (result.innerText > 5*a) {
lvl+=1;
a+=100;
}
document.getElementById('lvl').innerText = lvl;
var res = document.getElementById('result');
localStorage.setItem("myResult", res.innerText);
var level = document.getElementById('lvl');
localStorage.setItem("myLevel", level.textContent);
}
You were parsing result.innerText as a number, but its value, initially, was actually either NaN or nothing, both which end up being NaN. One fix is to just check if it parsed to a number, and if it didn't, fall back to 0.
I just basically changed that and removed some getElementByIds that, in my opinion, were redundant, check the addToResult function:
http://jsfiddle.net/owc26a0p/1/
function addToResult(pts) {
// NaN is falsy, so you can just use || to make a fallback to 0
var result = parseInt(resDiv.innerText, 10) || 0,
lvl = 0,
a = 100;
result = result + parseInt(pts, 10) || 0;
while (result > 5 * a) {
lvl += 1;
a += 100;
}
resDiv.innerText = result;
levelDiv.innerText = lvl;
localStorage.setItem("myResult", result);
localStorage.setItem("myLevel", levelDiv.textContent);
}
I ended up using jsFiddle since I couldn't always get jsBin to save my changes. Good luck.

Why won't .trim() work with me?

I'm having trouble getting this bit of javascript to work. Whenever I try it inputs nothing into my div. It just adds ?weight=NumberInputed&measure=lbsOrkgs&submit=Submit to the URL.
<h2>How small must you be to become a black hole?</h2>
<form name="form1">
<input id="howMuch" type="number" name="weight" placeholder="How much do you weigh?">
<input type="radio" name="measure" value="lbs" checked="true">lbs
<input type="radio" name="measure" value="kgs">kgs
<input type="submit" name="submit" value="Submit" onClick="calc(); return false;">
</form>
<br/>
<div id="insert"><div/>
<script language="JavaScript" type="Text/JavaScript">
function calc() {
var speedOfLight = 299792458.0;
var gravityConstantYoctometre = 66738400000000.0;
var finalHeight = 0.0;
var weight = document.form1.weight.value;
var measure = document.form1.measure.value;
measure = measure.trim();
if (measure !== "kgs"){
weight *= 0.4536;
}
finalHeight = (4.0 * gravityConstantYoctometre * weight)/Math.pow(speedOfLight,2);
finalHeight = (finalHeight).toFixed(5);
var message = '<em>You would have to be ' + finalHeight + ' yoctometres (1 metre x 10<sup>-24</sup>) tall before you would become a black hole.</em>';
document.getElementById('insert').innerHTML = message;
}
</script>
Without the .trim() function, it executes perfectly, except for the fact that it will not recognize measure equaling anything resembling 'lbs' or 'kgs'. What is happening here?
Here: http://jsfiddle.net/dJJjr/1/
function calc() {
var speedOfLight = 299792458.0;
var gravityConstantYoctometre = 66738400000000.0;
var finalHeight = 0.0;
var weight = document.getElementById("howMuch").value;
var radio = document.getElementsByName('measure');
var measure = ""
for(var i =0; i< radio.length; i++)
{
if(radio[i].checked)
measure = radio[i].value;
}
measure = measure.trim();
alert(measure); //For testing purpose
alert(weight); //For testing purpose
if (measure !== "kgs"){
weight *= 0.4536;
}
finalHeight = (4.0 * gravityConstantYoctometre * weight)/Math.pow(speedOfLight,2);
finalHeight = (finalHeight).toFixed(5);
var message = '<em>You would have to be ' + finalHeight + ' yoctometres (1 metre x 10<sup>-24</sup>) tall before you would become a black hole.</em>';
document.getElementById('insert').innerHTML = message;
}

Categories