Let's say you want to predefine a lot of buttons that are created by a button generator.
function createButton(name, func){
var btn = '<div class = "button" name = '+name+'/>';
$('.btn[name = "'+name+'"]').on('click', function(func){});
}
var butn1 = {
name : "exit",
func : func1
}
createButton(btn1);
Now if you had 100 buttons, this means a lot of variables. Is that bad? If it is, would this be better?
function chooseButton(name){
var btn;
switch(name){
case "exit":
btn = {
name : "exit",
func : func1
}
break;
case......
}
return btn;
}
var myBtn = chooseButton('exit');
createButton(myBtn);
If feel like it would be better to use a more general constructor for this sort of thing, assuming I've understood your question.
HTML
<div id="buttonContainer">
<button class="btn btn-type-a">Type A Button</button>
<button class="btn btn-type-b">Type B Button</button>
<!-- add further types -->
</div>
JS
var _functs = {
typeA: function () { alert('type A funct'); },
typeB: function () { alert('type B funct'); }
};
var _buttons = document.getElementById('buttonContainer')[0].childNodes;
for (var _i = 0; _i < _buttons.length; _i++) {
if (_buttons[_i].classList.contains('btn-type-a')) {
/*
node.classList.contains (not supported by IE < 10)
$(_buttons[_i]).hasClass('btn-type-a') if you're using jQuery
*/
_buttons[_i].addEventListener('click', _functs.typeA, false);
}
// other logic for other button assignment
};
Related
This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 1 year ago.
I'm getting an error that addeventlistener is not a function. I try to put it into a function but it didn't work. I also did this with btn.onclick event but I was getting the error:
"Uncaught TypeError: Cannot set property 'onclick'".
Any idea how to fix this, and why am I getting this error?
Here is the code:
<!-- try run this -->
<div class="input_wrpr">
<input class="enter_1" type="number" />
<input class="enter_2" type="number" />
<button data-combine="plus" class="combine_ plus" type="submit"> + </button>
<button data-combine="minus" class="combine_ minus" type="submit"> - </button>
<button data-combine="multi" class="combine_ multi" type="submit"> * </button>
<button data-combine="divi" class="combine_ divi" type="submit"> / </button>
<p class="result_"></p>
</div>
<script>
(function () {
"use strict";
var slc = (elemnt) => {
return document.querySelectorAll(elemnt);
};
var view = slc(".result_"),
btn = slc(".combine_"),
input1 = slc(".enter_1"),
input2 = slc(".enter_2");
btn.addEventListener("click", (e) => {
view.innerHTML = parseInt(input1.value) + parseInt(input2.value);
});
})(); // i know this code is not complete but i'm having an issue with eventlistener// i try this using loop but it's not working i mean i'm not getting any errors but result is not printing/
// i didn't try this using getAttribute because i don't know how to do with that especially with data- attribute.
// * this below code is working fine but i wanted to shorteren this code
// * i gusse you alredy have seen it that here i have to give eventlistener to each button and i'm using querySelector but above i'm using querySelectorAll.
// (function () {
// "use strict";
// var slc = (elemnt) => {
// return document.querySelector(elemnt);
// };
// var view = slc(".result_"),
// plus = slc(".plus"),
// minus = slc(".minus"),
// multi = slc(".multi"),
// divi = slc(".divi"),
// input1 = slc(".enter_1"),
// input2 = slc(".enter_2");
// plus.addEventListener("click", (e) => {
// view.innerHTML = parseInt(input1.value) + parseInt(input2.value);
// input1.value = "";
// input2.value = "";
// });
// minus.addEventListener("click", (e) => {
// view.innerHTML = parseInt(input1.value) - parseInt(input2.value);
// input1.value = "";
// input2.value = "";
// });
// multi.addEventListener("click", (e) => {
// view.innerHTML = parseInt(input1.value) * parseInt(input2.value);
// input1.value = "";
// input2.value = "";
// });
// divi.addEventListener("click", (e) => {
// view.innerHTML = parseInt(input1.value) / parseInt(input2.value);
// input1.value = "";
// input2.value = "";
// });
// })();
</script>
querySelectorAll returns a collection of node elements. If you have multiple elements that match you selector you have to iterate over this collection and set the listener for each element. If you are sure there is only one element that matches the selector you can use querySelector to get the first element that matches. Then you can set the listener directly to the element.
As previously noted querySelectorAll will return a nodelist rather than a specific node and thus assigning an event listener as you do will not work. Instead the nodelist should be iterated through and the event listener applied to each node. The idea of using a shortcut to document.querySelectorAll is one I do frequently but they are a little different as shown below. The remains of the code can be simplified a little ...
(function () {
"use strict";
var q=(e,n=document)=>n.querySelector(e);
var qa=(e,n=document)=>n.querySelectorAll(e);
var view = q(".result_");
var btns = qa(".combine_");
let clickhandler=(e)=>{
e.preventDefault();
let a=Number( q(".enter_1").value );
let b=Number( q(".enter_2").value );
let c;
switch(e.target.dataset.combine){
case 'plus':c=a+b;break;
case 'minus':c=a-b;break;
case 'multi':c=a*b;break;
case 'divi':c=a/b;break;
}
view.textContent=c.toString();
};
btns.forEach( btn=>btn.addEventListener("click", clickhandler ) );
})();
<!-- try run this -->
<div class="input_wrpr">
<input name='a' class="enter_1" type="number" />
<input name='b' class="enter_2" type="number" />
<button data-combine="plus" class="combine_ plus" type="submit"> + </button>
<button data-combine="minus" class="combine_ minus" type="submit"> - </button>
<button data-combine="multi" class="combine_ multi" type="submit"> * </button>
<button data-combine="divi" class="combine_ divi" type="submit"> / </button>
<p class="result_"></p>
</div>
Your btn is an array of node (your buttons), you can't do and addEventListener on a array? You need first to make a true array like that:
var btn = [...slc('.combine_')]
And then loop the array and create the events listener, like that :
for(let i=0; i<btn.length; i++){
btn[i].addEventListener("click", ()=>{})
}
I'm just trying to make a simple mobile-based calculator. So far I've managed to display the digits pressed up to a certain character limit. I'm trying to make it so it clears the digits within the h1 tag that serves as the display.
I've tried using .innerHTML = "", but that isn't working. How should I fix this?
HTML
<body>
<h1 id="display">Calculator</h1>
<div class="buttons container" id="arithmetic">
<button onclick="clear()" onkeypress="clear()">AC</button>
<button><sup>+</sup>⁄<sub>−</sub></button>
<button>%</button>
<button>÷</button>
<button onclick="number(7)" onkeypress="number(7)">7</button>
<button onclick="number(8)" onkeypress="number(8)">8</button>
<button onclick="number(9)" onkeypress="number(9)">9</button>
<button>×</button>
<button onclick="number(4)" onkeypress="number(4)">4</button>
<button onclick="number(5)" onkeypress="number(5)">5</button>
<button onclick="number(6)" onkeypress="number(6)">6</button>
<button>−</button>
<button onclick="number(1)" onkeypress="number(1)">1</button>
<button onclick="number(2)" onkeypress="number(2)">2</button>
<button onclick="number(3)" onkeypress="number(3)">3</button>
<button>+</button>
<button>.</button>
<button id="doubleSpace" onclick="number(0)" onkeypress="number(0)">0</button>
<button>=</button>
</div>
<div class="calcOptions container">
<button>Arithmetic</button>
<button>Algebra</button>
<button>Calculus</button>
<button>Statistics</button>
</div>
</body>
JavaScript
var currentQuery;
var pastQuery;
var queryLength = document.getElementById("display").innerHTML.length;
function number(n) {
if (document.getElementById("display").innerHTML == "Calculator") {
document.getElementById("display").innerHTML = "";
}
if (queryLength >= 15) {
} else {
currentQuery = document.getElementById("display").innerHTML;
currentQuery += n;
document.getElementById("display").innerHTML = currentQuery;
}
}
function clear() {
currentQuery = "";
document.getElementById("display").innerHTML = currentQuery;
}
You can't name a javascript function with clear(), and the value of queryLength should set after the document ready replace your code by:
var currentQuery;
var pastQuery;
var queryLength;
document.addEventListener("DOMContentLoaded", function(event) {
var queryLength = document.getElementById("display").innerHTML.length;
})
function number(n) {
if (document.getElementById("display").innerHTML == "Calculator") {
document.getElementById("display").innerHTML = "";
}
if (queryLength >= 15) {
} else {
currentQuery = document.getElementById("display").innerHTML;
currentQuery += n;
document.getElementById("display").innerHTML = currentQuery;
}
}
function clearValue() {
currentQuery = "";
document.getElementById("display").innerHTML = currentQuery;
}
and the clear button with:
<button onclick="clearValue()" onkeypress="clearValue()">AC</button>
The problem is that the name of your function clear is already used by this native function document.clear(). Here is a deeper look on why this native function is called and not your function: Is “clear” a reserved word in Javascript?.
The solution is to simply rename your clear() function to something else e.g. allcancel()
You can try using .innerText = "".
JS:
function ToggleShow(lang_option){
var elements = document.getElementsByClassName(lang_option);
var langs = document.getElementsByClassName("lang");
for(var i=0,l=elements.length;i<l;i++){
if(elements[i] in langs){
elements[i].style.display="block";
}else{
elements[i].style.display="none";
}
}
}
HTML:
<button type="button" class="btn btn-primary" data-toggle="button" aria-pressed="false" autocomplete="off" onclick="ToggleShow('lang-compiled')">
Compiled
</button>
<div class="lang lang-interpreted">Python 3</div>
<div class="lang lang-compiled">C</div>
works, but if I reverse the two display functions (change elements[i].style.display="block"; to elements[i].style.display="none"; and vice versa), the buttons stop functioning without any errors in console.
if(elements[i] in langs){ tests if the element in question is a property of the langs HTMLCollection, which is of course always false. If you wanted to check if the element is included in the HTMLCollection, you might turn the HTMLCollection into an array and use .includes:
function ToggleShow(lang_option) {
var elements = document.getElementsByClassName(lang_option);
var langs = [...document.getElementsByClassName("lang")];
for (var i = 0, l = elements.length; i < l; i++) {
if (langs.includes(elements[i])) {
elements[i].style.display = "block";
} else {
elements[i].style.display = "none";
}
}
}
Or, you might trim your function to something like this, to keep your code DRY:
function ToggleShow(lang_option) {
var langs = [...document.getElementsByClassName("lang")];
document.querySelectorAll('.' + lang_option).forEach(element => {
element.style.display = langs.includes(element)
? 'block'
: 'none';
});
}
we use in to check a property in an object, not a value. Just need to change the expression of if block to make the code work...
function ToggleShow(lang_option) {
var elements = document.getElementsByClassName(lang_option);
var langs = document.getElementsByClassName("lang");
for(var i=0,l=elements.length;i<l;i++) {
elements[i].style.display= langs.includes(elements[i]) ? "block" : "none";
}
}
I am trying to remove all the elements from my page with a specific class name, but for some reason only the alternate class gets deleted.
The code pen link is here
https://codepen.io/miller619/pen/WoVpdE
function prev(e) {
'use strict';
e.preventDefault();
var getID = document.getElementById("zone");
var removeXButtons = getID.getElementsByClassName("xbutton");
for (var i = 0; i < removeXButtons.length; i++) {
removeXButtons[i].parentNode.removeChild(removeXButtons[i]);
}
}
<div id="zone">
<input class="xbutton" name="xbtn" type="button" value="×">
<input class="xbutton" name="xbtn" type="button" value="×">
<input class="xbutton" name="xbtn" type="button" value="×">
</div>
<div id="pbtn" > <span class="glyphicon glyphicon-eye-open"></span> Delete all </div>
Where am I going wrong?
Just change the order of for loop and it'll work. Problem is as you remove an element from array, the order of element changes. Traversing the array backwards wont give you this problem.
function prev(e) {
'use strict';
e.preventDefault();
var getID = document.getElementById("zone");
var removeXButtons = getID.getElementsByClassName("xbutton");
for (var i = removeXButtons.length-1; i >=0 ; i--) {
removeXButtons[i].parentNode.removeChild(removeXButtons[i]);
}
}
}
If you want to loop forwards you can do this,
function prev(e) {
'use strict';
e.preventDefault();
var getID = document.getElementById("zone");
var removeXButtons = getID.getElementsByClassName("xbutton");
for (var i = 0; i < removeXButtons.length-1 ; i++) {
removeXButtons[i].parentNode.removeChild(removeXButtons[i]);
i--;
}
}
}
I have a dynamic button with looping and I have the onclick attribute function, like below :
for (var j=0; j<= 1; j++){
btndisplay= document.createElement("input");
btndisplay.setAttribute("type", "button");
btndisplay.setAttribute("style","height:80px;width:60px");
btndisplay.setAttribute("onclick", "myFunction"+ (j+1) +"(this.name)");
document.getElementById('divButtons'+(j+1)).appendChild(btndisplay);
}
How to simplify many functions as below, into a single function?
function myFunction1(name)
{
if (document.getElementById('value1').innerHTML==""){
document.getElementById('value1').innerHTML = name;
}
}
function myFunction2(name)
{
if (document.getElementById('value2').innerHTML==""){
document.getElementById('value2').innerHTML = name;
}
Use another parameter, one for the name and another for the id:
function myFunction(id, name)
{
if ( document.getElementById(id).innerHTML=="" )
document.getElementById(id).innerHTML = name;
}
you have created:
<input type="button" onclick="myFunction(this)">
<input...
...
the Function is:
function myFunction (that) {
if(that.innerHTML === "") {
that.innerHTML = that.name;
}
}