So I have a button on my website that looks like this:
<button id = "bgb">Toggle Background</button>
And I want this button to turn on and off the background in a box. Therefore I made a script in JavaScript to do this.
var bg = true;
document.querySelector("#bgb").onclick = function(){
const mb = document.querySelector(".Main-Box");
if (bg == true)
{
mb.style.background = "white";
bgb = false;
}
if (bg == false)
{
mb.style.background = "linear-gradient(45deg,#F17C58, #E94584, #24AADB , #27DBB1,#FFDC18, #FF3706)";
bgb = true;
}
}
However, when I click on the button, It tuns it off fine but when I want to turn it back on it doesn't work; any suggestions?
bg is always set true.
why you change "bgb"?
try
<script>
var bg = true;
document.querySelector("#bgb").onclick = function () {
const mb = document.querySelector(".Main-Box");
if (bg) {
mb.style.background = "red";
bg = false;
} else {
mb.style.background = "linear-gradient(45deg,#F17C58, #E94584, #24AADB , #27DBB1,#FFDC18, #FF3706)";
bg = true;
}
}
</script>
Here is a demo of what you want:
let bg = true;
document.querySelector("#bgb").onclick = function(){
const mb = document.querySelector(".Main-Box");
if (bg == true)
{
mb.style.background = "white";
bg = false;
}
else if (bg == false)
{
mb.style.background = "linear-gradient(45deg,#F17C58, #E94584, #24AADB , #27DBB1,#FFDC18, #FF3706)";
bg = true;
}
}
.Main-Box {
width: 100vw;
height: 100vh;
background: linear-gradient(45deg,#F17C58, #E94584, #24AADB , #27DBB1,#FFDC18, #FF3706);
}
<div class='Main-Box'>
<button id="bgb">Click Me!</button>
</div>
#cSharp already gave you a solution to your issue. However to make your entire code shorter and easier you could simply use: classList.toggle() and apply the changes by toggeling a CSS-Class on and off:
document.querySelector('#bgb').addEventListener("click", function() {
document.querySelector('.Main-Box').classList.toggle('class-name');
});
.Main-Box {
width: 100vw;
height: 100vh;
background: linear-gradient(45deg, #F17C58, #E94584, #24AADB, #27DBB1, #FFDC18, #FF3706);
}
.class-name {
background: white;
}
/* for visualisation only */
body {
margin: 0;
}
<div class='Main-Box'>
<button id="bgb">Click Me!</button>
</div>
If it is not necessary, I will not use global variables to control the state.
In addition, you can also create a new class attribute, and you only need to control the class when switching.
Below are examples of both approaches for your reference.
document.querySelector('input[type=button]').onclick = function() {
switchLinearGradientBackground('.main-box', 'linear-gradient');
}
function switchLinearGradientBackground(selector, switchClassName) {
const elems = document.querySelectorAll(selector);
for (let index = 0; index < elems.length; index++) {
elems[index].classList.toggle(switchClassName);
}
}
body {
display: flex;
}
.main-box {
flex-direction: column;
display: flex;
width: 200px;
height: 200px;
}
.linear-gradient {
background: linear-gradient(45deg, #F17C58, #E94584, #24AADB, #27DBB1, #FFDC18, #FF3706) !important;
}
<div class='main-box' />
<input type='button' value="switch background">
document.querySelector('input[type=button]').onclick = function() {
switchLinearGradientBackground('.main-box');
}
function switchLinearGradientBackground(selector) {
const elems = document.querySelectorAll(selector);
const grad = 'linear-gradient(45deg, #F17C58, #E94584, #24AADB, #27DBB1, #FFDC18, #FF3706)';
for (let index = 0; index < elems.length; index++) {
const style = elems[index].style;
style.background = style.background.length > 0 ? '' : grad;
}
}
body {
display: flex;
}
.main-box {
flex-direction: column;
display: flex;
width: 200px;
height: 200px;
}
<div class='main-box' />
<input type='button' value="switch background">
I am trying to understand function construction so I can cut down on my repeated code. All the snippets I have see deal with returning values and was hoping someone could shed some light on why this doesn't work.
<div id = 'box1' style = 'background-color: green; height: 100px; width: 50px' >
</div>
var box = $('#box1');
function pushCard(x){
if(x.style.opacity == 0.5){
x.style.opacity = 1;
}
else {
x.style.opacity = 0.5;
}
}
box.click(pushCard(box));
You don't want to call the function as you pass it. You can just pass the function, then when you click it will pass the event. The element is the event target
var box = $('#box1');
function pushCard(event) {
let x = event.target
if (x.style.opacity == 0.5) {
x.style.opacity = 1;
} else {
x.style.opacity = 0.5;
}
}
box.click(pushCard);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='box1' style='background-color: green; height: 100px; width: 50px'>
</div>
You can also use this to get the clicked object:
var box = $('#box1');
function pushCard() {
if (this.style.opacity == 0.5) {
this.style.opacity = 1;
} else {
this.style.opacity = 0.5;
}
}
box.click(pushCard);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='box1' style='background-color: green; height: 100px; width: 50px'>
</div>
I am creating chinese checkers, I use span tag to create circles. Added only left padding to the top corner. I have two questions:
1) Why rows seem to have distance between them, but not columns.
2) To fix 1) I added padding-left, but instead of adding distance the padding became part of the circle, why?
Here's the link how it looks:
Here's part of code:
.player0{
height: 40px;
width: 40px;
padding-right: 5px;
background-color: transparent;
border-radius: 50%;
display: inline-block;
}
divs += "<span class='player"+fullBoardArr[fullArrIter]+" 'onclick='send()'></span>"
divs += "<div class='clear_float'> </div>" //for separation of rows
As I said in comments, you need to use margin instead of padding.
I would not use "clear_float" (I assume this is about the float CSS property). Instead wrap elements that belong in the same row, in a separate div element.
From the image you included, it seems that you have a problem in aligning the cells. You can use many ways to solve this, but as your board is symmetric horizontally (ignoring the colors), you can just use text-align: center.
I had some fun in creating JavaScript logic for the board itself. You may find some aspects interesting to reuse:
class Cell {
constructor(rowId, colId) {
this._value = 0;
this.rowId = rowId;
this.colId = colId;
this.elem = document.createElement("span");
this.elem.className = "cell";
this.selected = false;
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
this.elem.style.backgroundColor = ["", "grey", "blue", "red"][value];
}
toggleSelected() {
this.selected = !this.selected;
this.elem.classList.toggle("selected", this.selected);
}
}
class Board {
constructor() {
this._container = document.createElement("div");
this._container.className = "board";
this.elemMap = new Map;
this.grid = [[0,0,0,0,2,0,0,0,0,0,0,0,0],
[0,0,0,0,2,2,0,0,0,0,0,0,0],
[0,0,0,0,2,2,2,0,0,0,0,0,0],
[0,0,0,0,2,2,2,2,0,0,0,0,0],
[3,3,3,3,1,1,1,1,1,4,4,4,4],
[0,3,3,3,1,1,1,1,1,1,4,4,4],
[0,0,3,3,1,1,1,1,1,1,1,4,4],
[0,0,0,3,1,1,1,1,1,1,1,1,4],
[0,0,0,0,1,1,1,1,1,1,1,1,1]];
// create the data structure for the game and produce the corresponding DOM
this.grid.forEach((row, rowId) => {
let div = document.createElement("div");
row.forEach((value, colId) => {
if (!value--) return;
let cell = row[colId] = new Cell(rowId, colId);
cell.value = value;
div.appendChild(cell.elem);
this.elemMap.set(cell.elem, cell);
});
this._container.appendChild(div);
});
}
set container(elem) {
elem.appendChild(this._container);
}
getEventCell(e) {
return this.elemMap.get(e.target);
}
set selected(cell) {
if (this._selected) {
this._selected.toggleSelected();
this._selected = null;
}
if (!cell) return;
cell.toggleSelected();
this._selected = cell;
}
get selected() {
return this._selected;
}
move(cellFrom, cellTo) {
// TODO: Implement the real move rules here
if (!cellFrom.value) return; // must move a piece
if (cellTo.value) return; // capturing not allowed
cellTo.value = cellFrom.value;
cellFrom.value = 0;
board.selected = null;
}
}
let container = document.querySelector("#container");
let board = new Board();
board.container = container;
container.addEventListener("click", e => {
let cell = board.getEventCell(e);
if (!cell) return; // click was not on a cell
if (!board.selected || cell.value) {
board.selected = cell;
} else {
board.move(board.selected, cell);
}
});
.board {
text-align: center;
margin-left: auto; margin-right: auto;
}
.cell {
height: 15px;
width: 15px;
margin: 0px 2px;
border: 1px solid;
border-radius: 50%;
display: inline-block;
}
.selected {
border-color: orange;
}
<div id="container"></div>
You can click to select a piece and then click again on an empty spot to move it there.
Use margin instead of padding:
.player0{
height: 40px;
width: 40px;
margin-right: 5px;
background-color: transparent;
border-radius: 50%;
display: inline-block;
}
As an easy-to-remember quick reference, margin changes the position starting from outside the element border, padding from the inside
I'm making a simple full viewport scroller. You can change sections by triggering wheel event.
To prevent the eventhandler from firing many times in row and skipping pages, I've added a timer, calculating the difference between date.now() stored in variable and date.now() inside the eventHandler. This happens mostly if you spam scrolling, it makes you have to wait about 3 seconds to scroll again instead of 200ms. How to prevent this from happening?
document.ready = (fn) => {
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading"){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
document.ready(() => {
const SECTIONS = document.querySelectorAll('.section');
let current;
let onWheelTimeout = 'poop';
let time = Date.now()
// initialize first section as active
_.first(SECTIONS).classList.add('active');
document.addEventListener('wheel', onWheel)
function goSectionUp() {
const current = document.querySelector('.active');
current.classList.remove('active');
if(current.previousElementSibling) {
current.previousElementSibling.classList.add('active');
} else {
_.last(SECTIONS).classList.add('active');
}
}
function goSectionDown() {
const current = document.querySelector('.active');
current.classList.remove('active');
if(current.nextElementSibling) {
current.nextElementSibling.classList.add('active');
} else {
_.first(SECTIONS).classList.add('active');
}
}
function onWheel(e) {
const now = Date.now()
const diff = now - time;
time = now;
if(diff > 200) {
if(e.deltaY < 0) {
onScroll('up')
} else {
onScroll('down')
}
}
}
function onScroll(direction) {
if(direction === 'up') {
goSectionUp()
} else {
goSectionDown()
}
};
});
html {
box-sizing: border-box;
overflow: hidden;
width: 100%; height: 100%;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
padding: 0; margin: 0;
overflow: hidden;
height: 100%; width: 100%;
position: relative;
}
#page {
width: 100%; height: 100%;
transition: all 1s ease;
transform: none !important;
}
.section {
height: 100vh; width: 100%;
opacity: 0;
visibility: hidden;
position: absolute;
top: 0;
left: 0;
transition: all .7s ease-in-out;
}
.section:nth-of-type(1) {
background-color: red;
}
.section:nth-of-type(2) {
background-color: aquamarine;
}
.section:nth-of-type(3) {
background-color: blueviolet;
}
.section:nth-of-type(4) {}
.active {
opacity: 1; visibility: visible;
}
#button {
position: sticky;
top: 0; left: 100px;
z-index: 1000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
<div id="page">
<div class="section">one</div>
<div class="section">two</div>
<div class="section">three</div>
<div class="section">four</div>
</div>
It seems like what you want is a debounce function. I'd recommend using this one, by David Walsh:
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
Usage
var myScrollFunction = debounce(function() {
// All the taxing stuff you do
}, 250);
document.addEventListener('wheel', myScrollFunction);
To answer why your code doesn't work as expected: The mouse wheel produces a series of continuous events while it is scrolling, so your time diff is constantly < 200. Here's an example of it working "properly" (though the best answer is still a true debounce function as stated above).
JSBin example
https://jsbin.com/cuqacideto/edit?html,console,output
I am learning JS and have created a carousel with a caption underneath.
How do I get the Prev/Next buttons to affect the caption as well as the image? I've tried combining the if statements in several ways but have failed miserably.
Relevant HTML:
<span id="prev" class="arrow">❮</span>
<div class="karussell" id="karussell">
<img class="karu" name="esislaid">
</div>
<span id="next" class="arrow">❯</span>
<div class="caption">
<h3 id="esikiri"></h3>
</div>
JS:
var p = 0;
var s = 0;
var esileht = [];
var aeg = 5000;
var kiri = [];
//Image List
esileht[0] = 'img/tooted/raamat/graafvanalinn2016.jpg';
esileht[1] = 'img/tooted/kaart/kaart_taskus_esipool.jpg';
esileht[2] = 'img/tooted/kaart/graafkaart_esikylg.jpg';
//Captions
kiri[0] = 'Raamat "Tallinn. Graafiline vanalinn"';
kiri[1] = 'Tallinna vanalinna graafiline kaart (suur formaat)';
kiri[2] = 'Tallinna vanalinna graafiline kaart (väike formaat)';
// Left and Right arrows
//Eelmine
function eelmine(){
if (p === 0){
p = esileht.length;
}
p = p - 1;
return esileht[p];
}
//Jargmine
function jargmine(){
p = p + 1;
p = p % esileht.length;
return esileht[p];
}
document.getElementById('prev').addEventListener('click', function (e){
document.querySelector('#karussell img').src = eelmine();
}
);
document.getElementById('next').addEventListener('click', function (e) {
document.querySelector('#karussell img').src = jargmine();
}
);
//Change Image
function changePilt (){
document.esislaid.src = esileht[p];
if(p < esileht.length -1){
p++;
} else {
p = 0;
}
setTimeout("changePilt()", aeg);
}
//Change Caption
function changeKiri(){
document.getElementById('esikiri').innerHTML = kiri[s];
if(s < kiri.length - 1){
s++;
}
else {
s = 0;
}
setTimeout('changeKiri()', aeg);
}
document.body.onload = function(){
changePilt();
changeKiri();
};
CSS, just in case:
.karussell {
position: relative;
width: 100%;
max-height: 600px;
overflow: hidden;
}
.arrow {
cursor: pointer;
position: absolute;
top: 40%;
width: auto;
color: #00A7E0;
padding: 16px;
font-weight: bold;
font-size: 18px;
border-radius: 3px;
transition: 0.6s ease;
}
#next {
right: 0;
}
#prev {
left: 0;
}
.arrow:hover {
background-color: rgba(0,0,0,0.8);
}
.caption {
text-align: center;
color: #00A7E0;
padding: 2px 16px;
}
.karu {
max-width: 75%;
animation-name: fade;
animation-duration: 2s;
}
#keyframes fade {
from {opacity: 0.4}
to {opacity: 1}
}
#media (max-width:767px){.karu{max-width: 95%;}}
I made a fiddle to try to illustrate (had to paste the js into the html tab to gt it to work for some reason): Fiddle
Really you just need to use the .innerHTML() feature and do exactly what you already have. Either create a eelmine2() function (or something like that) and call it again, grabbing the content from kiri[] or instead just return the p and use it in two places:
document.getElementById('prev').addEventListener('click', function (e){
document.querySelector('#karussell img').src = eelmine();
document.querySelector('#esikiri').innerHTML = eelmine2();
});
function eelmine2(){
if (p === 0){
p = kiri.length;
}
p = p - 1;
return kiri[p];
}
or
document.getElementById('prev').addEventListener('click', function (e){
var change = eelmine();
document.querySelector('#karussell img').src = esileht[change];
document.querySelector('#esikiri').innerHTML = kiri[change];
});
function eelmine(){
if (p === 0){
p = kiri.length;
}
p = p - 1;
return p;
}
This assumes your code is using the same global vars inside public functions that you have set up in your Fiddle. You should fix that to have variables passed into the functions before going live with all of this, but I'm not addressing that any further here.