JavaScript Calculator - How to get numbers into input field? - javascript

So I have assigned all my numbers a class of numbers and all my operators a class of operators with ids specific to their operation. Every item is within a div tag.
Full data here: jsfiddle
<div class="number clear" id="clear"><h1>C</h1></div>
<div class="number" id="entry"><input type="number"></div>
<div class="number seven"><h1>7</h1></div>
<div class="number eight"><h1>8</h1></div>
<div class="number nine"><h1>9</h1></div>
<div class="operate divide" id="divide"><h1>/</h1></div>
So the above is just a glimpse of the HTML. My CSS works perfectly fine but I'm struggling with the JavaScript. I've put in a for loop to pull from all the numbers in the HTML to do an addEventListener for onclick. I feel confident in the for loop but I could definitely be wrong.
Right now I have the following:
let number = document.getElementsByClassName("number");
let operate = document.getElementsByClassName("operate");
let entry = document.getElementById("entry");
let clear = document.getElementById("clear");
let sub=document.getElementById("sub");
let multiply = document.getElementById("mul");
let divide = document.getElementById("divide");
let add = document.getElementById("plus");
for (let i=0; i<numbers.length; i++) {
numbers[i].addEventListener("click", function(entry)){
let inputValue = entry[0].innerHTML;
let buttonValue = this.html;
if (buttonValue === "C") {
entry[0].innerHTML = "";
} else {
entry[0].innerHTML += buttonValue;
}
}
}
function (entry){
}
I know I need to run a function in the for loop but for the life of me I'm drawing blanks as to what to enter to push the values from the div into the entry field for the calculation. Right now if I click on any of the buttons nothing happens, clearly as there's no function. Any insight on how to adjust this to get something to populate would be appreciated.

let numbers = document.getElementsByClassName("number");
let entry = document.getElementById("entry");
for (let i=0; i<numbers.length; i++) {
numbers[i].addEventListener("click", function(){
let buttonValue = this.textContent;
if (buttonValue === "C") {
entry.innerHTML = "0000";
} else {
entry.innerHTML = (entry.innerHTML+buttonValue).substr(-4);
}
});
}
.number {
display:inline-table;
}
<h1><div id="entry">0000</div></h1>
<div class="number"><h1>1</h1></div>
<div class="number"><h1>2</h1></div>
<div class="number"><h1>3</h1></div><br>
<div class="number"><h1>4</h1></div>
<div class="number"><h1>5</h1></div>
<div class="number"><h1>6</h1></div><br>
<div class="number"><h1>7</h1></div>
<div class="number"><h1>8</h1></div>
<div class="number"><h1>9</h1></div><br>
<div class="number "><h1>C</h1></div>
You just mixed up some variable names and used non existent properties...

As mentioned by Jonas in his answer, there are a bunch of issues in your current code - including some syntax issues. So I decided replace your event handler completely, and write it using jQuery - as it really comes in handy in such cases.
The event handler looks like this:
$(".number").on("click", function(event){
var num = $(this).text();
console.log(num);
if(num != 'C') {
var currentNumber = $("#entryNum").val();
$("#entryNum").val(currentNumber.toString() + num.toString());
} else {
$("#entryNum").val('');
}
});
The logic of the event handler remains quite similar to your original logic, but I have just simplified it using jQuery. Also, to allow for faster access to the input element, I gave it an ID entryNum:
<div class="number" id="entry"><input type="number" id="entryNum"></div>
Here's the updated fiddle: https://jsfiddle.net/Nisarg0/L9mL4v3a/6/

Not certain about exact logic or expected result, though there are issue with selecting appropriate element and syntax errors
for (let i = 0; i < numbers.length; i++) {
numbers[i].addEventListener("click", function(event) {
// select the `<input>` child element of `entry` here, not `entry[0]`
// and use `.value` property
let inputValue = entry.querySelector("input").value;
// you want `.textContent` here, not `.innerHTML`
let buttonValue = this.textContent;
if (buttonValue === "C") {
entry.innerHTML = "";
} else {
entry.innerHTML += buttonValue;
}
}) // include closing `)` at `.addEventListener()` call
}

I just implement Press and Clear function.
Learn and do it!
1.Add id for inputfield
<div class="number" id="entry"><input id="entryText" type="number"></div>
2.Do it!
let numbers = document.getElementsByClassName("number");
let entryText = document.getElementById("entryText");
for (let i=0; i<numbers.length; i++) {
numbers[i].addEventListener("click", function(event){
let buttonValue = event.toElement.innerText;
if (buttonValue === "C") {
entryText.value = "";
} else {
entryText.value += buttonValue;
}
});
}

There are several issues in your code:
Your event listener accepts a parameter called entry, which overwrites the entry variable in the outer scope. The first parameter of the event listener that you pass to addEventListener contains information about the click event (which you normally don't need). So remove the entry parameter from the event listener.
The value of this in an event listener is a reference to the element that you bound the event listener to. It won't have a property called html.
You declare a variable called number, but use a variable called numbers.
numbers[i].addEventListener("click", function(entry)){ results in a syntax error. Remove the second ) between parameter list and the function body.
function (entry){} results in a syntax error, because function statements require a name. Just remove it, it's superfluous.
That said, get some inspiration from the following code snippet:
const input = document.querySelector('input');
document.querySelectorAll('.number').forEach(function (button, index) {
button.addEventListener('click', function () {
input.value += index + 1;
});
});
<input type="number">
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="number">4</button>

Related

Removing selected child from an div element

My question aims to find the simplest way for removing a child from a div element. In this case either Apple, Orange or Banana. Which means you can put the cursor on one of these words and then click delete child.
The only way Iam thinking is doing it in two steps:
Returning the index of the selected child with returnIndexOfChild() (custom built)
Using the removeChild method
I mean when you are having a big text java script engine has to loop through the whole text to find the index. Is there a more direct way like deleting anchorNode by selection object?
//html part
<div contentEditable="true" id="editableField"><b>Apple</b><i>Orange</i><b>Banana</b></div>
<button onclick="deleteChild()"> Delete</button>
//javascript part
var selection = document.getSelection();
myDiv = document.getElementById("editableField");
//Returns index of selected child (1)
function returnIndexOfChild(){
let i = 0;
for (i; i < myDiv.childNodes.length; i++){
if(selection.anchorNode.parentElement === myDiv.childNodes[i]){
console.log(i);
break;
};
}
return i;
}
//Removing Child(2)
function deleteChild (){
myDiv.removeChild(myDiv.childNodes[returnIndexOfChild()]);
}
You can just call remove() on the element itself
function deleteChild (){
const selection = document.getSelection();
selection.anchorNode?.parentElement?.remove();
}
<div contentEditable="true" id="editableField"><b>Apple</b><i>Orange</i><b>Banana</b></div>
<button onclick="deleteChild()"> Delete</button>
2 solutions:
//html part
<div contenteditable="true" id="editableField">
<li>Apple</li>
<li>Orange</li>
<li>Banana</li>
<li>potato</li>
<li>grape</li>
<li>egg</li>
<li>milk</li>
</div>
<input type="text" class="input" />
<button class="button">Delete</button>
<script>
const myDiv = document.querySelector("#editableField");
const input = document.querySelector(".input");
const btn = document.querySelector(".button");
// first way thanks to event bubbling
myDiv.addEventListener("click", (ev) => {
ev.target.remove();
});
// second way, by iterating through items
btn.addEventListener("click", () => {
// The "onclick="..." in the html is old solution, new and better is addEventListener(...)"
const myDivChildren = [...myDiv.children]; // The "..." is spread operator, "myDiv" is HTMLCollection, an array like object in orter ot iterate ovet it I created array by spreading it
const inputValue = input.value || myDivChildren.length - 1; // take input value if exist, if not then last index so remove last item
myDivChildren.forEach((el, i) => {
if (i == inputValue) {
el.remove(); // When indexes match then delete
}
return; // When indexes match then stop executing loop
});
input.value = "";
});
I got rid of getSelection(), it complicates removing items, do you care about using getSelection()? Should I use it in the answer?

A variable in an anonymous function under EventListener staying undefined despite being previously declared and then defined clearly

So I'm making a basic to-do list using only HTML and JS and for some reason, when I go to add an item to the list, the variable that I'm using to select the empty "li" element is returning as "undefined" after I execute the function under the EventListener for the "clear" button. Could someone help out here pls. HTML and JS attached below:
let todos = [];
let add = document.querySelector("#add");
let remove = document.querySelector("#remove")
let clear = document.querySelector("#clear")
let todolist = document.querySelector("#todolist")
let addTodo;
let clearedTodo;
let newTodo;
add.addEventListener("click", function() {
addTodo = prompt("Enter the item you would like to add.")
todos.push(addTodo);
todolist.innerHTML += "<li></li>"
newTodo = document.getElementsByTagName("li")[todos.length - 1]
newTodo.textContent = addTodo;
})
remove.addEventListener("click", function() {
let removeTodo = prompt("Enter the index number of the item you would like to remove.") - 1;
let removedTodo = document.getElementsByTagName("li")[removeTodo]
removedTodo.remove();
todos.splice(removeTodo, 1);
})
clear.addEventListener("click", function() {
todos = [];
document.querySelector("ol").remove();
document.querySelector("div").innerHTML += '<ol id="todolist"></ol>'
console.log("To Do list was cleared.")
})
<h1>The Ultimate To Do List</h1>
<p>Click on an item to mark as done.</p>
<button id="add">ADD</button>
<button id="remove">REMOVE</button>
<button id="clear">CLEAR</button>
<div id="clearer">
<ol id="todolist">
</ol>
</div>
Thanks.
The problem is in your clear function. Mostly it looks good except for one problem that causes the major error. When you remove all the "ol" element, your todolist var loses reference, since it has nothing to point to. You would have to redeclare it.
But there is an easier way to fix this. Remove these lines:
document.querySelector("ol").remove();
document.querySelector("div").innerHTML += '<ol id="todolist"></ol>'
Use this line instead:
todolist.innerHTML = "";
Now the todo list in the DOM is also cleared and your todolist var still points to what its supposed to.

Outputting an object to a page that keeps close function

I posted this question before, among others. But it was suggested I need to ask a more specific or focused question.
I am working on an output history log on a single page. And I want to make it so each output it's self is contained in box object that can be closed or deleted individually. Like this.
Now I have managed to get everything working to the point where it will nicely output to a box with a close button. However the close button it's self will not function in this case.
So, I am trying to output it like this...
HTML:
<p>History log:</p><br><div style="white-space:pre-wrap"><ul
id="outputListItem" class="boxcontainer"></ul></div>
SCRIPT:
document.getElementById("Add").onclick = function(e) {
convertOutput();
}
function convertOutput(){
//this is the part I have been trying to get working
convertOutput.addEventListener('close', function() {
this.parentElement.style.display = 'none';
}
});
var output = document.getElementById("output").value;
var li = document.createElement('li');
li.className = "containedboxes";
var dateTime = todayDateTime();
li.innerHTML = "<time id='time'>" + dateTime +"</time><br /> <br />"+ output
+"<br /><br /><span class='close'>×</span>";
document.getElementById('outputListItem').prepend(li);
}
And the script to close the box:
var closebtns = document.getElementsByClassName("close");
var i;
for (i = 0; i < closebtns.length; i++) {
closebtns[i].addEventListener("click", function() {
this.parentElement.style.display = 'none';
});
}
It was suggested to me on the last question I posed I should use convertOutput() right after addEventListener() loop immediately after it. If this is how you do it, i am still quite new to JavaScript, so not sore how to properly do this. I created a fiddle for this also, but for some reason I can't get the script to run properly in the fiddle, But all the code is there to see.
I am looking to solve this using vanilla JavaScript.
I created an example for you. Hopefully this helps you get going :) A couple things to note, I use a data attribute to store the index for the item in the array, so you can delete it when you click on the list item.
document.addEventListener('DOMContentLoaded', function(){
let nameEl = document.querySelector("#name");
let submitEl = document.querySelector("#submit-name");
let historyEl = document.querySelector(".history-list");
let historyList = [
{ name: 'Mitch'},
{ name: 'Max'},
{ name: 'Mike'},
];
function addToList(arr) {
// Clear up list and then update it
while(historyEl.firstChild) {
historyEl.removeChild(historyEl.firstChild);
}
// Update the list with the historyList
for(let item in historyList) {
let name = historyList[item].name;
let listContent = document.createElement("li");
listContent.textContent = name;
// We will use the index to remove items from the list
listContent.setAttribute('data-value', item);
listContent.addEventListener("click", removeFromList)
historyEl.appendChild(listContent);
}
}
function removeFromList(index) {
// Takes the index of the object, and will later remove it
console.log("Removed Item " + this.dataset.value);
historyList.splice(index, 1);
addToList(historyList);
}
addToList(historyList);
submitEl.addEventListener("click", function(event) {
if(nameEl.value) {
// Add the name to the start of the history list array.
historyList.unshift({ name: nameEl.value})
nameEl.value = '';
// Update the dom with the new array
addToList(historyList);
}
});
});
<label for="name">Type Name</label>
<input type="text" name="name" id="name">
<button id="submit-name">Submit Name</button>
<ul class="history-list"></ul>
Hopefully this gives you a good idea on how to get the task done and let me know if you have any questions :)
Your boxes don't respond to the click event simply because your script crashes before the events even get attached to it.
The following block right at the beginning:
document.getElementById("Add").onclick = function(e) {
convertOutput();
}
tries to add a click listener to the HTML element Add which does not exist. If you either remove the code block or add the appropriate element your boxes will have it's click functionality.

change events stop working when a new change event is added to a different element in JS

I am programmatically generating some HTML, and trying to add a listener for a change event the elements.
This works fine for the first object, but as soon as I add the second object the first one stops firing the event.
In the code example below you'll see the updateLabel function only fires for the last object created. I need it to fire for all of the objects.
I have tried with .onchange, and with an event listener, but get the same results.
Any help much appreciated.
<html>
<body>
<div id="main">
<!--this is where all the generated HTML goes -->
</div>
</body>
<script>
mainDomElement = document.querySelector("#main");
for (var count = 0; count < 4; count++)
{
var labelId = 'Label' + count;
newHTML = '<input class="accordionLabel" type="text" id="' + labelId + '" value="' + labelId + '"/>'
currentHTML = mainDomElement.innerHTML
mainDomElement.innerHTML = newHTML + currentHTML
labelDomObj = document.querySelector('#' + labelId);
//labelDomObj.addEventListener("change", updateLabel);
labelDomObj.onchange = function(event){updateLabel(event)}
}
function updateLabel(event)
{
alert(event.target.value);
}
</script>
</html>
It may be best to take a different approach when creating and adding DOM elements. Try this.
for (var count = 0; count < 4; count++)
{
var labelId = 'Label' + count,
newHTML = document.createElement('input');
newHTML.type = 'text';
newHTML.value = labelId;
newHTML.id = labelId;
newHTML.addEventListener('onchange', updateLabel, false);
mainDomElement.appendChild(newHTML);
}
your code explanation
// this takes the main DOM element and stores a copy of it in the variable.
currentHTML = mainDomElement.innerHTML
/*
This is taking the innerHTML property of the main DOM element. It is then
trying to concatenate the newly created DOM to that stored in the mainDomElement
variable. I don’t think this is what you want.
*/
mainDomElement.innerHTML = newHTML + currentHTML
// this is trying to select an element from the DOM that does not exist yet.
labelDomObj = document.querySelector('#' + labelId);
// This is trying to add an event listener to an element that does not exist.
labelDomObj.onchange = function(event){updateLabel(event)}
You are also missing sim icons from your variable declarations.
This looks like an issue with closures, where initializing var count = 0 within the for loop ultimately results in only the last value getting bound to the event handler.
I believe moving the initialization outside of the loop will fix your issue. Also, ES6 introduced the let keyword that scopes the variable in the way you are expecting:
for (let count = 0; count < 4; count++) { }
See this excellent introduction to javascript closures for more information.

Dynamical Calculator Javascript

It is a calculator which has spans from which I want to take a values(1,2,3, etc.) and two fields: First for displaying what user is typing and the second is for result of calculation.
The question how to get values so when I click on spans it will show it in the second field
Here is the code.
http://jsfiddle.net/ovesyan19/vb394983/2/
<span>(</span>
<span>)</span>
<span class="delete">←</span>
<span class="clear">C</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span class="operator">÷</span>
....
JS:
var keys = document.querySelectorAll(".keys span");
keys.onclick = function(){
for (var i = 0; i < keys.length; i++) {
alert(keys[i].innerHTML);
};
}
var keys = document.querySelectorAll(".keys span");
for (var i = 0; i < keys.length; i++) {
keys[i].onclick = function(){
alert(this.innerHTML);
}
}
keys is a NodeList so you cannot attach the onclick on that. You need to attach it to each element in that list by doing the loop. To get the value you can then simple use this.innerHTML.
Fiddle
This should get you started.. you need to get the value of the span you are clicking and then append it into your result field. Lots more to get this calculator to work but this should get you pointed in the right direction.
Fiddle Update: http://jsfiddle.net/vb394983/3/
JavaScript (jQuery):
$(".keys").on("click","span",function(){
var clickedVal = $(this).text();
$(".display.result").append(clickedVal);
});
You can set a click event on the span elements if you use JQuery.
Eg:
$("span").click(
function(){
$("#calc").val($("#calc").val() + $(this).text());
});
See:
http://jsfiddle.net/vb394983/6/
That's just to answer your question but you should really give the numbers a class such as "valueSpan" and the operators a class such as "operatorSpan" and apply the events based on these classes so that the buttons behave as you'd expect a calculator to.
http://jsfiddle.net/vb394983/7/
var v="",
max_length=8,
register=document.getElementById("register");
// attach key events for numbers
var keys = document.querySelectorAll(".keys span");
for (var i = 0; l = keys.length, i < l; i++) {
keys[i].onclick = function(){
cal(this);
}
};
// magic display number and decimal, this formats like a cash register, modify for your own needs.
cal = function(e){
if (v.length === self.max_length) return;
v += e.innerHTML;
register.innerHTML = (parseInt(v) / 100).toFixed(2);
}
Using JQuery will make your life much easier:
$('.keys span').click(function() {
alert(this.innerHTML);
});

Categories

Resources