I'm struggling on write my code.
What I am trying to do:
Insert random numbers every few sec next to the "show" elements, when its say its available.
Expected Result
When its "Not available", no numbers can be inserted in.
When its "Available", numbers can be inserted in.
var myVar = setInterval(breakdown, 2000);
/*
var myVar1 = setInterval(random, 1000);
function random() {
var n = Math.floor((Math.random() * 10) + 1);
let loops = Array.from(document.querySelectorAll('.show'));
for (const loop of loops) {
if () {
loop.innerHTML = n;
}
}
}
*/
function breakdown() {
let elems = Array.from(document.querySelectorAll('.demo'));
for (const elems1 of elems) {
let d = Math.random();
if (d < 0.50) {
let str = "Available";
text = str.fontcolor("green");
x = true;
} else {
let str = "Not Available";
text = str.fontcolor("red");
y = false;
}
elems1.innerHTML = text;
}
}
<p id="demo1" class="demo">
<p id="show1" class="show"></p>
<p id="demo2" class="demo">
<p id="show2" class="show"></p>
<p id="demo3" class="demo">
<p id="show3" class="show"></p>
In order to read other elements' (such as sibling in this case) state ('Available' or 'Not Available') for switching work, you can call the previousSibling of the target property then access its innerHTML. Read more about previousSibling dom property. https://www.w3schools.com/jsref/prop_node_previoussibling.asp
fiddle
Related
I have two buttons - one that sends two messages with a one-second interval, and the other only sends one message, with the second left as undefined (this will be clearer once you see the code). How do I stop undefined from showing up?
var credits = 0;
var currency = 'Skatter';
function addLog(logBefore, logAfter) {
var par = document.createElement("p");
var node1 = document.createTextNode(logBefore);
var node2 = document.createTextNode(logAfter);
par.appendChild(node1);
var element = document.getElementById("logs");
// Here you can also use element.childNodes.length
const count = document.getElementById("logs").getElementsByTagName("p").length;
if (count >= 18) {
element.removeChild(element.childNodes[0]);
}
element.appendChild(par);
if (node2 !== undefined) {
setTimeout(function() {
console.log(logBefore)
console.log(logAfter)
var par = document.createElement("p");
var node2 = document.createTextNode(logAfter);
par.appendChild(node2);
var element = document.getElementById("logs");
// Here you can also use element.childNodes.length
const count = document.getElementById("logs").getElementsByTagName("p").length;
if (count >= 8) {
element.removeChild(element.childNodes[0]);
}
element.appendChild(par);
}, 1000);
}
};
<button onclick="addLog('Hunt begun', 'Hunt successful! You now have ' + credits + ' ' + currency)">HUNT</button>
<br>
<button onclick="addLog('Resources sold')">SELL</button>
<div id="logs" style="display: flex; flex-direction: column-reverse;"></div>
On the second button you are passing just one argument to the addLog function.
The core problem with your code is that you are asking if node2 variable you have created is falsey (evaluates to false), but a text node will never evaluate to false because it is an object which holds values
// try this in your browser console
>>> if (document.createTextNode(undefined)) {
console.log("not null")
}
>>> "not null" //output
If you want to check if the program gave a value for the second parameter (logAfter), then you should, explicitly do this instead, like:
if (logAfter !== undefined) {
// do stuff
}
You should change the conditional to check if the direct log logAfter is not undefined, not the textNode. This will fix you issue...
var credits = 0;
var currency = 'Skatter';
function addLog(logBefore, logAfter) {
var par = document.createElement("p");
var node1 = document.createTextNode(logBefore);
var node2 = document.createTextNode(logAfter);
par.appendChild(node1);
var element = document.getElementById("logs");
// Here you can also use element.childNodes.length
const count = document.getElementById("logs").getElementsByTagName("p").length;
if (count >= 18) {
element.removeChild(element.childNodes[0]);
}
element.appendChild(par);
if (logAfter !== undefined) {
setTimeout(function() {
var par = document.createElement("p");
var node2 = document.createTextNode(logAfter);
par.appendChild(node2);
var element = document.getElementById("logs");
// Here you can also use element.childNodes.length
const count = document.getElementById("logs").getElementsByTagName("p").length;
if (count >= 8) {
element.removeChild(element.childNodes[0]);
}
element.appendChild(par);
}, 1000);
}
};
<button onclick="addLog('Hunt begun', 'Hunt successful! You now have ' + credits + ' ' + currency)">HUNT</button>
<br>
<button onclick="addLog('Resources sold')">SELL</button>
<div id="logs" style="display: flex; flex-direction: column-reverse;"></div>
I am repeatedly looping through an array, my aim is to stop the loop and printout a specific element in the array and display it through span id="fruit". please see code below :
var title = ['233249864597', '233209425159', '233201112221', '233546056136', '233266549303', '233209409846', '233501345825', '233248446422', '233546112136', '233541006033', '233502089334', '233552476293', '233268222280', '233202240898'];
var i = 0; // the index of the current item to show
var animate = setInterval(function() {
// setInterval makes it run repeatedly
document
.getElementById('fruit')
.innerHTML = title[i++];
// get the item and increment
if (i == title.length) i = 0;
// reset to first element if you've reached the end
}, 15);
function stop() {
clearInterval(animate);
}
<h1>THE WINNER IS : </h1>
<h1><span id="fruit"></span></h1>
<center><button onclick="stop()">STOP</button></center>
You mean
const title = ['233249864597', '233209425159', '233201112221', '233546056136', '233266549303', '233209409846', '233501345825', '233248446422', '233546112136', '233541006033', '233502089334', '233552476293', '233268222280', '233202240898'];
const winner = title[3]; // for example
var i = 0; // the index of the current item to show
var animate = setInterval(function() {
// setInterval makes it run repeatedly
document
.getElementById('fruit')
.innerHTML = title[i++];
// get the item and increment
if (i == title.length) i = 0;
// reset to first element if you've reached the end
}, 15);
function stop() {
clearInterval(animate);
document
.getElementById('fruit')
.innerHTML = winner;
}
<h1>THE WINNER IS : </h1>
<h1><span id="fruit"></span></h1>
<center><button onclick="stop()">STOP</button></center>
var title = ['233249864597', '233209425159', '233201112221', '233546056136', '233266549303', '233209409846', '233501345825', '233248446422', '233546112136', '233541006033', '233502089334', '233552476293', '233268222280', '233202240898'];
var i = 0; // the index of the current item to show
var animate = setInterval(function() {
// setInterval makes it run repeatedly
//document.getElementById('fruit').innerHTML = title[i++];
// get the item and increment
if (i == title.length) i = 0;
// reset to first element if you've reached the end
}, 15);
function stop() {
clearInterval(animate);
document.getElementById('fruit').innerHTML = title[i++];
}
<h1>THE WINNER IS : </h1>
<h1><span id="fruit"></span></h1>
<center><button onclick="stop()">STOP</button></center>
How about this?
I changed the numbers to fruits because.. well... I just wanted to write out some fruits.
But they can be changed back to numbers ofc.
var fruits = ['Apple', 'Banana', 'Pineapple', 'Orange', 'Kiwi', 'Watermelon'];
var i = 0; // the index of the current item to show
var animate = setInterval(function() {
i++
document
.getElementById('fruit')
// use modulus operator to stay inside array
.innerHTML = fruits[i % fruits.length];
}, 15);
function stop() {
clearInterval(animate);
}
<h1>THE WINNER IS : </h1>
<h1><span id="fruit"></span></h1>
<center><button onclick="stop()">STOP</button></center>
Today in class we were given a task to 'recreate' the jQuery functionality (I don't know why, I guess the teacher is sadistic).
We were given the following instruction:
Using only pure javascript (not even ECMEScript 2015) create a function '$' that will receive a tag / id / class.
If you're given only one token [ e.g $("#id)] return the suitable elements.
If you're given more than one token [ e.g $("nav div div p")]- search hierarchically for the last token.
Input: $('nav div p');
Goal: Get all the p elements that has a div above them which has a nav above the div.
if (query.split(" ").length > 1) {
var first = query.split(" ")[0];
var rest = query.split(" ").slice(1);
var curr_elements;
if (first.match(/^#.*/i)) {
curr_elements = (document.getElementById(first.substring(1)));
} else if (query.match(/^\..*/i)) {
curr_elements = document.getElementsByClassName(first.substring(1));
} else if (query.match(/^\w.*/i)) {
curr_elements = document.getElementsByTagName(first);
}
curr_elements = [].slice.call(curr_elements);
for (var e = 0; e < curr_elements.length; e++) {
if (curr_elements[e].hasChildNodes()) {
for (var i = 0; i < rest.length; i++) {
var temp = rest[i];
var children;
if (temp.match(/^#.*/i)) {
children = (document.getElementById(temp.substring(1)));
} else if (temp.match(/^\..*/i)) {
children = document.getElementsByClassName(temp.substring(1));
} else if (temp.match(/^\w.*/i)) {
children = document.getElementsByTagName(temp);
}
alert(children);
//curr_elements += children;
}
}
}
this.elements = curr_elements;
} else {
if (query.match(/^#.*/i)) {
this.elements.push(document.getElementById(query.substring(1)));
} else if (query.match(/^\..*/i)) {
this.elements = document.getElementsByClassName(query.substring(1));
} else if (query.match(/^\w.*/i)) {
this.elements = document.getElementsByTagName(query);
}
}
<nav>
<p id="1"></p>
</nav>
<nav>
<div>
</div>
<p>
<div>
<p id=2></p>
</div>
</p>
</nav>
<nav>
<div>
<p id="3"></p>
<p id="4"></p>
<div>
</div>
</div>
</nav>
<nav>
<div>
<div>
<div>
<p id="5"></p>
</div>
</div>
</div>
</nav>
Variables:
query: the first arg, is tag / id / class name.
curr_elements: array-to-be for temporarily storing the elements I get.
this.elements: the final HTMLCollection.
The part relating to single token ($("p");) works fine, but I'm having trouble figuring out how to recurse / iterate over the elements to get the paragraphs.
Hoping to get someone's idea / advice on how to continue.
Your code is fairly solid, you just are not using recursion which in this case is quite useful.
I've changed your code to use a recursive approach:
function $(selector, context) {
if (!selector) return false;
// context should be an array of previous nodes we have found. If it's undefined, assume the single-item array [document] as the starting context
if (!context) context = [document];
var s = selector.split(" ");
var first = s.shift();
var curr_elements = [], els;
for (var i=0; i < context.length; i++) {
var c = context[i];
// make sure els gets converted into a real array of nodes
if (first.match(/^#.*/i)) {
els = [c.getElementById(first.substring(1))];
} else if (first.match(/^\..*/i)) {
els = [].slice.call(c.getElementsByClassName(first.substring(1)));
} else if (first.match(/^\w.*/i)) {
els = [].slice.call(c.getElementsByTagName(first));
}
curr_elements = curr_elements.concat(els);
}
// if there are more items in s, then curr_elements is the context in which to find them. Otherwise, curr_elements is the array of elements we were looking for.
if (s.length) return $(s.join(" "), curr_elements);
return curr_elements;
}
var a = $(".test span");
console.log(a);
<div class="test">
<span>1</span><span>2</span><span>3</span>
</div>
<div class="not_test">
<span>4</span><span>5</span><span>6</span>
</div>
<p class="test">
<span>7</span><span>8</span><span>9</span>
</p>
I am trying to build a function that changes values in innerHTML of elements which have one class name, but different number values.
as in:
<div class="ingredient-assignment__quantity">5</div>
<div class="ingredient-assignment__quantity">300</div>
<div class="ingredient-assignment__quantity">250</div>
And I want a calculation (same for all) to run through all of them and then change the innerHTML of each to the result of each.
as in:
calcuation = 5 * innerHTML;
<div class="ingredient-assignment__quantity">25</div>
<div class="ingredient-assignment__quantity">1500</div>
<div class="ingredient-assignment__quantity">1250</div>
My JS function looks like this:
function ingredientChange (){
var portionsBefore = document.getElementById('portions');
var ingredients = document.getElementsByClassName('ingredient-assignment__quantity');
function getPortions(event) {
const getID = event.target.id;
if (getID == "minus") {
var y = Number(portionsBefore.innerHTML) - 1;
}
else {
var y = Number(portionsBefore.innerHTML) + 1;
}
changeIngredients(y);
portionsBefore.innerHTML = y;
}
function changeIngredients(y) {
var arr = Object.keys(ingredients).map((k) => ingredients[k])
for(var i = 0; i < arr.lenght; i++){
var changeValues = Number(arr[i].innerHTML) / Number(portionsBefore.innerHTML);
var changedValues = Number(changeValues) * y;
}
}
function addEventListeners () {
document.getElementById('minus').addEventListener('click', getPortions, false);
document.getElementById('plus').addEventListener('click', getPortions, false);
}
addEventListeners();
}
ingredientChange();
And everything except for the for loop works fine.
I cant find, whats wrong with the for loop
You have a typo in your for loop
arr.lenght should be arr.length.
Here's what I'm trying to do:
Type initials (e.g. MS,AK,LT) by clicking on "Enter Names". This saves a string, which I then turn into an array (nameArray) in order to get each set of initials. After reordering these randomly, I want to place some of the initials into the textareas, but that's where things go wrong.
Here's what's wrong:
the initials display for a moment, then disappear after the function executes. (ALSO, I'm trying to have a div (with text "randomizing...") that is otherwise hidden, show itself for 4 seconds (4000 ms) while the initials are being reordered to indicate as such. That's what the setTimeout is for...but that doesn't work either. The div disappears along with the text). Why are these only in coordination with the execution of the function?
Here's the JS code:
var nameArray;
window.onload = pageLoad;
function pageLoad() {
$("#randomizingNotification").hide();
$("#prev_arrow").click(prevUser);
$("#next_arrow").click(nextUser);
$("#enter_names").click(orderNames);
}
function orderNames() {
nameArray = getNames();
randomizeNames();
displayNames();
}
function getNames() {
var initialsString = prompt("Please enter initials, separated by a comma (e.g LK,AS,NM)");
nameArray = initialsString.split(",");
return nameArray;
}
function randomizeNames() {
$("#randomizingNotification").show();
var timer = setTimeout(function(){randomize(nameArray);},4000);
$("#randomizingNotification").hide();
clearTimeout(timer);
}
function randomize(array) {
for (var i = 0; i < array.length; i++ ) {
var randNum = Math.floor(array.length*Math.random()) //random number between 0 and length of array (rounded down
var temp = array[i];
array[i] = array[randNum];
array[randNum] = temp;
}
}
function displayNames() {
var curr, up, prev, current, upcoming, previous;
curr = 0;
up = 1;
prev = null
current = nameArray[curr];
upcoming = nameArray[up];
$("#upcoming_pick").val(upcoming);
$("#current_pick").val(current);
}
Here's the relevant HTML code:
<body>
<div id="header">
<div id="randomizeNotContDiv">
<div id="randomizingNotification">randomizing...</div>
</div>
<div id="page_title"><h1>Welcome to Classtech Shift Scheduler!</h1></div>
<div id="helper_functions_div">
<div id="enter_names_div">
Enter Names
</div>
</div>
<div id="main_content">
<div id="name_tracker">
<div><img src="Images/prev_arrow.png"/></div>
<textarea name="upcoming_pick" cols="10" rows="1" class="picker_names" id="upcoming_pick"></textarea>
<textarea name="current_pick" cols="10" rows="1" class="picker_names" id="current_pick"></textarea>
<textarea name="previous_pick" cols="10" rows="1" class="picker_names" id="previous_pick"></textarea>
<div><img src="Images/next_arrow.png"/></div>
</div>
You've got at least few issues, but the main problem is the structure of your setTimeout. A setTimeout is like an AJAX call in that it's non-blocking. Anything inside the function you pass to it will only execute when the timer is done, while code that comes after it will execute immediately.
I've reorganized the hiding of your randomization message and the displayNames function to go inside of the setTimeout function and things work fine.
Here it is in a fiddle: http://jsfiddle.net/nate/LB6dz/
And here's the code:
var nameArray;
window.onload = pageLoad;
function pageLoad() {
$("#randomizingNotification").hide();
$("#enter_names").click(orderNames);
}
function orderNames(event) {
// Prevent the link's default action
event.preventDefault();
nameArray = getNames();
randomizeNames();
}
function getNames() {
var initialsString = prompt("Please enter initials, separated by a comma (e.g LK,AS,NM)");
nameArray = initialsString.split(",");
return nameArray;
}
function randomizeNames() {
$("#randomizingNotification").show();
var timer = setTimeout(function (){
randomize(nameArray);
// These items need to be inside the timeout, so they only run once it's done
$("#randomizingNotification").hide();
displayNames();
}, 4000);
// No need to clearTimeouts after they're done... they only run once
// clearTimeout(timer);
}
function randomize(array) {
for (var i = 0; i < array.length; i++ ) {
var randNum = Math.floor(array.length*Math.random()) //random number between 0 and length of array (rounded down
var temp = array[i];
array[i] = array[randNum];
array[randNum] = temp;
}
}
function displayNames() {
var curr, up, prev, current, upcoming, previous;
curr = 0;
up = 1;
prev = null
current = nameArray[curr];
upcoming = nameArray[up];
$("#upcoming_pick").val(upcoming);
$("#current_pick").val(current);
}