How to make reusable button - javascript

I'm new to JavaScript and I want to create a button that, when clicked, will change the position of the object. But after clicking once, nothing else works. Below I have provided the code with the very essence of the problem, and my code where I want to apply it. Maybe someone will tell you how to make a restart button correctly, instead of constantly creating new divs.
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<style>
button {
position: relative;
}
</style>
</head>
<body>
<button>Add new position</button>
<script>
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
btn.style.top = '50px';
});
</script>
</body>
</html>
MY PROJECT
const yes = document.getElementById('yes');
const no = document.getElementById('no');
const body = document.querySelector('.body');
const message = document.querySelector('.message');
const reset = document.querySelector('.panel__close')
const bodyMessage = document.querySelector('.body__message')
const randomNum = Math.floor(Math.random() *100) +1;
yes.addEventListener('click', () => {
body.innerHTML = '';
const paraLox = document.createElement('p');
paraLox.textContent = 'Congratulation, Jaba Loshara Ebaniy!';
paraLox.style.fontSize = '3rem';
paraLox.style.textAlign = 'center';
paraLox.style.fontWeight = '1000';
paraLox.style.color = 'red';
body.appendChild(paraLox);
reset.addEventListener('click', () => { // reset button
paraLox.parentNode.removeChild(paraLox);
const bodyError = document.createElement('div');
bodyError.setAttribute('class', 'body__error-image');
bodyMessage.appendChild(bodyError);
const bodyErrorImage = document.createElement('img');
bodyErrorImage.setAttribute('src', 'error.png')
bodyErrorImage.style.width = '50px';
bodyErrorImage.style.height = '50px';
bodyError.appendChild(bodyErrorImage);
const bodyText = document.createElement('div');
bodyText.setAttribute('class', 'body__text');
bodyText.textContent = 'Jaba Lox?';
bodyMessage.appendChild(bodyText);
const bodyButtons = document.createElement('div');
bodyButtons.setAttribute('class', 'body__buttons');
bodyMessage.appendChild(bodyButtons);
const bodyButton1 = document.createElement('div');
bodyButton1.setAttribute('class', 'body__button');
bodyButton1.setAttribute('id', 'yes');
bodyButton1.textContent = 'Yes';
bodyButtons.appendChild(bodyButton1);
const bodyButton = document.createElement('div');
bodyButton.setAttribute('class', 'body__button');
bodyButton.setAttribute('id', 'no');
bodyButton.textContent ='No';
bodyButtons.appendChild(bodyButton);
});
});
no.addEventListener('click', () => {
no.style.position = 'relative';
no.style.top = randomNum + 'px';
no.style.bottom = randomNum + 'px';
no.style.left = randomNum + 'px';
no.style.right = randomNum + 'px';
});

From what I understand, you want the button to keep moving down with each click. In that case, the callback currently keeps setting the distance from the top to 50px. All you need to do is have the function add 50 to the current value.
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<style>
button {
position: relative;
}
</style>
</head>
<body>
<button>Add new position</button>
<script>
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
btn.style.top = ((parseInt(btn.style.top,10) || 0) + 50) + 'px';
});
</script>
</body>
</html>
Test it here
Things to note:
The value is saved as a string with a pixel suffix, i.e. "50px", so we'll use parseInt() to convert it to an int we can add to.
Before setting the style, AKA before the first click, its value is "" not 0, which doesn't work with parseInt(), hence the OR || operator.

Related

Change global variables by js function

I wanna change a group of scrolling images by clicking on button. question here is how to change the global variables by these function
please see the attached codes,
I wanna initiate the stack() function when onload and change the scrolling images set by onclick;
Should I add an onload event and seperately call the stack() funtions, only using the local var?
thanks,
Joe
var images = imagest;
function softtissue(){
var images = imagest;
}
function bone(){
var images = imagebone;
}
function lung(){
var images = imagelung;
}
var stack = new ImageStack({
images: images,
height: '512px',
width: '512px'
});
document.querySelector('.example').appendChild(stack);
// how to use the funciton on line 94
// for questions email felix#demont.is
var images10 = [
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg"
];
var imagesbone = [
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg",
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg"
];
var imageslung = [
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg",
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg",
"https://igu3ss.files.wordpress.com/2012/09/chess_king_4.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Chess_piece_-_Black_queen.JPG/130px-Chess_piece_-_Black_queen.JPG", "https://asmoodle.asmadrid.org/blog/s16240/wp-content/uploads/sites/56/2014/12/protourney_knight_black_400.jpg",
"https://thumbs.dreamstime.com/x/chess-knight-white-background-29811348.jpg",
"http://cdn.craftsy.com/upload/3703789/pattern/115774/full_7439_115774_ChessKnightMachineEmbroideryDesign_1.jpg"
];
function ImageStack(options) {
var self = this;
self.img_array = options.images;
self.stack = document.createElement('div');
self.stack.style.overflow = 'auto';
self.stack.style.maxWidth = '100%';
self.stack.style.height = options.height;
self.stack.style.width = options.width;
self.stack.style.backgroundSize = 'cover'
self.stack.style.position = 'relative';
var typeRegex = /(\D+)/
var sizeType = options.height.match(typeRegex)[0]
var numberRegex = /(\d+)/
self.height_number = Number(options.height.match(numberRegex)[0])
self.wrapper = document.createElement('div');
for (var i = 0; i < self.img_array.length; i++) {
var image = document.createElement('img');
image.src = self.img_array[i];
image.style.display = 'none';
image.style.position = 'absolute';
image.style.width = options.width;
image.style.height = options.height;
image.style.top = 0;
image.style.left = 0;
image.dataset.iid = i;
self.wrapper.appendChild(image);
}
self.image_elements = self.wrapper.querySelectorAll('img');
self.scrollobject = document.createElement('div');
self.scrollobject.style.width = '100%';
self.scrollobject.style.position = 'absolute';
self.scrollobject.style.zIndex = '2';
self.img_count = (self.img_array.length > 15) ? self.img_array.length : 15;
self.scrollobject_height = Math.floor(0.1 * self.img_count * self.height_number);
self.scrollobject.style.height = self.scrollobject_height + sizeType;
self.scrollUpdate = function(e) {
self.height_number = self.stack.getBoundingClientRect().height
self.scrollobject_height = Math.floor(0.1 * self.img_count * self.height_number);
var sT = self.stack.scrollTop
var hn05 = self.img_array.length - 1
var hh = (self.scrollobject_height - self.height_number) / hn05
scrollval = Math.floor(sT / (hh))
self.currentimg = self.image_elements[scrollval].src
self.stack.style.backgroundImage = 'url(' + self.currentimg + ')';
}
self.stack.addEventListener('scroll', self.scrollUpdate);
self.currentimg = self.image_elements[0].src
self.stack.style.backgroundImage = 'url(' + self.currentimg + ')';
window.addEventListener('resize', function() {
var stackRect = self.stack.getBoundingClientRect()
console.log(stackRect)
self.height_number = stackRect.height
self.scrollobject_height = Math.floor(0.1 * self.img_array.length * self.height_number);
self.stack.style.width = stackRect.width + 'px'
self.stack.style.eight = stackRect.width + 'px'
})
self.stack.appendChild(self.wrapper);
self.stack.appendChild(self.scrollobject);
return self.stack;
}
/*problems here*/
/*global var*/
var images = images10;
/*local var*/
function softtissue() {
var images = images10;
}
function bone() {
var images = imagesbone;
}
function lung() {
var images = imageslung;
}
/*how to switch the local var in global function*/
var stack = new ImageStack({
images: images,
height: '512px',
width: '512px'
});
document.querySelector('.example').appendChild(stack);
<div>
<button id="softtissue" type="button" onclick="softtissue();return false" class="button">
Soft Tissue</button>
<button id="bone" type="button" onclick="bone(); return false;" class="button">
Bone</button>
<button id="lung" type="button" onclick="lung(); return false" class="button">
Lung</button>
</div>
<div class="example">
</div>
var images = imagebone; never changes the global but it initializes a local variable. It creates a local variable images inside the function. You shouldn't use var inside functions
function softtissue(){
images = imagest;
}
function bone(){
images = imagebone;
}
function lung(){
images = imagelung;
}
A better approach would be to use images as a parameter to a general function instead of a separate function specific to the image. That way you can add unlimited amounts of images without the need to write an extra function for each image.
So inside the change_image() function, the correct image string just gets taken from the button clicked, instead of there being a function to set some global variable.
// ImageStack mockup
function ImageStack( config ) {
this.images = config.images;
this.height = config.height;
this.width = config.width;
}
ImageStack.prototype.node = function() {
return document.createElement( 'div' ).appendChild( document.createTextNode( this.images ));
};
// click event for all the buttons
function change_image( event ) {
var image_type = event.target.getAttribute( 'data-type' );
var stack = new ImageStack({
images: `image${ image_type }`,
height: '512px',
width: '512px'
});
render( stack.node() );
}
// render function.
// Could be inside the click event, but I would prefer seperate functions.
function render( image ) {
document.querySelector('.example').appendChild( image );
}
Array.from( document.querySelectorAll( 'button' )).forEach(function( button ) {
button.addEventListener( 'click', change_image );
});
<nav>
<button data-type="st">ST</button>
<button data-type="bone">BONE</button>
<button data-type="lung">LUNG</button>
</nav>
<section class="example"></section>
EDIT:
Since the question text got updated and no longer includes the line Or is there a better approach?, this answer might seem weird.
One approach is changing the varibility of the image
adding variability ="hidden" in the imagestack and after creating these three boxes, onclickfunction onlick choose which one to show

Small animation works only with .data?

I made this small animation so I can practice, its purpose is to add the last letter to the beginning of the word.
I've thought that it should work with ".innerTEXT" instead of .data too, but it doesn't. Can you explain why and how does .data work? On w3schools I've learnt that .data returns a URL, so wouldn't this be supposed to work with .innerTEXT?
document.addEventListener('DOMContentLoaded', function() {
const div = document.getElementById('1');
const node = div.childNodes[0];
let text = node.data;
setInterval(() => {
text=text[text.length - 1] + text.substring(0, text.length-1);
node.data = text;
}, 100);
});
<div id="1">asdf</div>
See the working example with the innerText below.
document.addEventListener('DOMContentLoaded', function() {
const div = document.getElementById('1');
let text = div.innerText;
setInterval(() => {
text=text[text.length - 1] + text.substring(0, text.length-1);
div.innerText = text;
}, 100);
});
<div id="1">asdf</div>
You can also do this with the node like you did, but you should use textContent:
document.addEventListener('DOMContentLoaded', function() {
const div = document.getElementById('1');
const node = div.childNodes[0];
let text = node.textContent;
setInterval(() => {
text=text[text.length - 1] + text.substring(0, text.length-1);
node.textContent = text;
}, 100);
});
<div id="1">asdf</div>

correct way for onClick Binding in Button

I am working on a coding exercise and I was done with it and tried to play around a little.
This is the html i have:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Test</h1>
<script src="jquery.js"></script>
<script src="test.js"></script>
<script>
function runAfter() {
alert("HI!");
var p = document.createElement("p");
p.id = "msg";
p.innerHTML = "TEST!";
document.body.innerHTML += "<br />";
document.body.appendChild(p);
console.log(p.innerHTML);
};
//window.onload=runAfter;
</script>
</body>
</html>
And the js file:
"use strict";
var Widget = {
init: function Widget(width, height) {
this.width = width || 50;
this.height = height || 50;
this.$elem = null;
},
render: function ($where) {
if (this.$elem) {
this.$elem.css({
width: this.width + "px",
height: this.height + "px"
}).appendTo($where);
}
}
};
var Button = Object.create(Widget);
Button.config = function config(width, height, label) {
this.init(width, height);
this.label = label || "ClickMe";
this.$elem = $("<button>").text(this.label);
};
Button.build = function ($where) {
this.render($where);
this.$elem.click(this.onClick.bind(this));
};
Button.onClick = function (evt) {
console.log("Button '" + this.label + "' clicked!");
this.updateMessage("Button '" + this.label + "' clicked!");
};
Button.updateMessage = function (msg) {
var p = document.getElementById("msg");
p.innerHTML = msg;
};
function run() {
let $body = $(document.body);
//create
let btn1 = Object.create(Button);
let btn2 = Object.create(Button);
//initialize
btn1.config(125, 30, "Hello");
btn2.config(150, 40, "World");
//build
btn1.build($body);
btn2.build($body);
};
$(document).ready(run);
if you leave //window.onload=runAfter; as is in html, you can see the problem in the console that comes from Button.onClick function. But the console.log works giving
"Button '" + this.label + "' clicked!"
But if you uncomment it, that function doesn't work.
What is going wrong? Is the dynamic this binding going out of scope to somewhere else ?
The runAfter() appends elements to dynamically generated html page from test.js.
What should happen is, the two buttons should work as expected with console.log and <p> para with id=msg printing out the same as console.log
It works if you comment out
document.body.innerHTML += "<br/>";
and replace it with
document.body.appendChild(document.createElement("br"));
Edit with explanation:
What's happening is that when you use document.body.innerHTML +=, you're taking the innerHTML as a string, adding to that string, and then replacing the entire innerHTML with the new string. So you're not adding to what's already there (the way appendChild() does), you're removing all of it and replacing it.
When you remove the buttons, the click handlers attached to them are gone. And the scripts don't run again after the innerHTML is replaced, so the click handlers are never reattached.

Returning Set of Styles

<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="practise.css"/>
<script type="text/javascript" src="practise.js"></script>
</head>
<body>
<div id="items"><p id="help">Hello World</p></div>
<script>
var para=document.getElementById('help');
var check=true;
//want to return these styles whenever mouse is clicked
function toggle(){
if(check){
para.style.color="#EEFFCC";
para.style.textAlign="center";
para.style.fontSize="1em";
}else{
para.style.color="#223311";
para.style.textAlign="center";
para.style.fontSize="4em";
}
check=!check;
}
para.onclick=toggle();
</script>
</body>
</html>
The code i want to make is that it toggles between two sets of Styles whenever mouse is licked on 'para' element. But i couldn't figure out how to return the styles to the 'para.onclick' call below the function.
Currently you are doing:
para.onclick = toggle();
which means that para.onclick will be the result of executing toggle().
What you want to do is assign toggle to para.onclick:
para.onclick = toggle;
The difference is this:
function result() {
return 2;
}
var res = result();
// res = 2
var fnRes = result;
// fnRes = function() { return 2; }
Just create a little function when you click the onClick it calls your toggle, like so para.onclick = function() {}.
var para = document.getElementById('help');
var check = true;
function toggle() {
if (check) {
para.style.color = "blue";
para.style.textAlign = "center";
para.style.fontSize = "1em";
} else {
para.style.color = "red";
para.style.textAlign = "center";
para.style.fontSize = "4em";
}
check = !check;
}
para.onclick = function() {
toggle()
};
<div id="items">
<p id="help">Hello World</p>
</div>

Function with if-else doesn't work properly

I made a function which should disable a button if a variable isn't greater than or equal to another one. This function is run every second on a setInterval(), and the first variable to compare is also incremented by one on the setInterval(). But, the function (evitarNegs()), isn't working properly, and the button is always disabled. Sorry that part of the code is in spanish.
Javascript:
var GmB = {cantidad: 0, perSec: 1};
function Upgrade (pb, ps) {
this.precioBase = pb;
this.perSec = ps;
this.cantidad = 0;
this.precio = pb;
}
Upgrade.prototype.comprar = function() {
GmB.cantidad = GmB.cantidad - this.precio;
GmB.perSec = GmB.perSec + this.perSec;
this.cantidad++;
document.getElementById("gmb").innerHTML = GmB.cantidad;
this.precio = Math.ceil(this.precioBase*Math.pow(1.15, this.cantidad));
evitarNegs();
};
function loop() {
GmB.cantidad = GmB.cantidad + GmB.perSec;
document.getElementById("gmb").innerHTML = GmB.cantidad;
evitarNegs();
}
var upg = new Upgrade(10, 1);
var boton1 = document.getElementById("boton1");
boton1.disabled = true;
window.setInterval(loop, 1000);
//Problematic function
function evitarNegs() {
if (!(GmB >= upg.precio)) {
boton1.disabled = true;
}else {
boton1.disabled = false;
}
}
boton1.onclick = function() {
upg.comprar();
};
HTML:
<html>
<head>
<title>Gummy Bears</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<p id="gmb">0</p>
<button id="boton1" type="button">Upgrade 1</button>
<script src="main.js"></script>
</body>
</html>
You are comparing GmB to upg.precio, but GmB is an object. So you want
function evitarNegs() {
if (!(GmB.cantidad >= upg.precio)) {
boton1.disabled = true;
} else {
boton1.disabled = false;
}
}
However, this can be written much easier as
function evitarNegs() {
boton1.disabled = GmB.cantidad < upg.precio;
}
Fiddle: http://jsfiddle.net/4rRmp/
It seems that you are comparing an object to an integer in GmB >= upg.precio. You probably have to replace it by GmB.cantidad >= upg.precio.

Categories

Resources