In my HTML I want to place a word within the id=“button__anfang“
<p class="card-text" id="text__anfang"></p>
For this I have an array with words to chose from. A function: ausgabe_start choses randomly a word and place it there by click on a button.
This is the function which places the randomly choosen word in the node with the id "text-anfang".
let ausgabe_start = () => {
arrWords.push(textAnfang.textContent = start[number_start]);
}
For some reason it pushes the word into another array. [number_start] is the index which takes a word from the array start. It is randomly.
When I don't like the word, I want to click the button again, to get a new one. And I don't want a complete page reload
How can I make the function chose again from the array and place the word within id="text__anfang"?
I tried a query within the function like in pseudocode:
If text__anfang.length != "0" delete text__anfang.
Pls. take a look at this codepen
In the callback function for the click event listener you're actually pushing the assignment to textAnfang.textContent to the array arrWords.
The text itself is defined by the result of start[number_start]); where start is your array of words and number_start a random integer. If you want to have another random index, you need to give number_start another value inside the callback handler like:
let ausgabe_start = () => {
let number_start = Math.floor((Math.random() * 2));
textAnfang.textContent = start[number_start];
}
The drawback here is that it might return the self random word again because there is no check to make sure that it doesn't happen. You can workaround this by putting the assignment inside a do-while loop which repeates itself as long as the random word and the current value of textAnfang are equal.
let ausgabe_start = () => {
let tempStr;
do {
number_start = Math.floor((Math.random() * 2));
tempStr = start[number_start];
}
while (tempStr == textAnfang.textContent);
textAnfang.textContent = tempStr;
}
Related
I'm writing a hangman game. With the help of Google I have a function to check if a letter is in the word, but I don't understand how, although I never declare the parameter "chosenLetter" of my function, this is able to give "chosenLetter" exactly the value of the specific letter I click on. Nor how "getElementById(chosenLetter)" can pick exactly the letter I click on to disable the button.
Same thing with the "guessedWord" function, where "letter" is never declared, yet it selects a letter to check for in the "guessed" array
let answer = '';
let maxWrong = 5;
let mistakes = 0;
let guessed = [];
let wordStatus = null;
function guessedWord() {
wordStatus = answer.split('').map(letter => (guessed.indexOf(letter) >= 0 ? letter : '_')).join('');
document.getElementById('word').innerHTML = wordStatus;}
function generateButtons() {
let buttonsHTML = 'abcdefghijklmnopqrstuvwxyz'.split('').map(letter =>
`
<button
class = "btn"
id = '` + letter + `'
onClick = "handleGuess('` + letter + `')"
>
` + letter + `
</button>
`).join('');
document.getElementById('alphabet').innerHTML = buttonsHTML;}
function handleGuess(chosenLetter) {
if (guessed.indexOf(chosenLetter) === -1) {
guessed.push(chosenLetter)
} else {
null;
}
document.getElementById(chosenLetter).setAttribute('disabled', true);
if (answer.indexOf(chosenLetter) >= 0) {
guessedWord();
checkIfGameWon();
} else if (answer.indexOf(chosenLetter) === -1) {
mistakes++;
updateMistakes();
checkIfGameLost();
}}
As I'm new at javascript, I'm generally trying to understand how is it possible that parameters not declared can seem to declare themselves so specifically? I don't know if I'm asking the wrong question, but that's the only thing in the code which I can't understand nor explain
You need to read this documentation first.
It says
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
If we try to break the following statement in separate statements,
wordStatus = answer.split('').map(letter => (guessed.indexOf(letter) >= 0 ? letter : '_')).join('');
You will find,
let splittedAnswer = answer.split(''); // This will split the answer string and crate an array with all the characters in answer.
const callbackFunction = (letter) => {
return guessed.indexOf(letter) >= 0 ? letter : '_';
}
let newArray = splittedAnswer.map(callbackFunction);
let joinedString = newArray.join('');
As you can see you are declaring a callback function. You are passing that function to the array.map() method. Now the array.map() method will call the function with 3 params currentItemInTheArray, currentIndex, theSourceArray. As you have declared only the first param in your callbackFunction i.e. currentElementInTheArray you will get the first param. You could declare your callback array like this,
const callbackFunction = (item, index, arr) => {
console.log(item);
console.log(index);
console.log(arr);
}
And now if you call
[1,2,3].map(callbackFunction);
You will get the following output,
1 //currItem
0 //index
[1,2,3] //source array
2 //currItem
1 //index
[1,2,3] //source array
3 //currItem
2 //index
[1,2,3] //source array
But you are doing it inline, that is why you were not following. I hope now it is clear to you.
This is how functions work, you pass an argument as an input and to use that argument in your function you use parameters in the function definition which act as placeholders for your input and then you can use the parameters anywhere inside your function.
Example: In the function guessedWord(), you are using a map function which takes a callback function as an argument. So the work letter is actually the parameter of the callback function and parameters don't need declaration they are just placeholders.
generateButtons is going to insert into the HTML element "alphabet" something that looks like this:
<button
class = "btn"
id = 'a'
onClick = "handleGuess('a')"
>
a
</button>
<button
class = "btn"
id = 'b'
onClick = "handleGuess('b')"
>
b
</button>
...
Those onClick handlers will be function that pass the various letters as the first (and only) argument to handleGuess.
handleGuess is a function declared to take a single parameter, which is known internally to the function as chosenLetter. But when you call it, you do not have to pass it a variable with the name chosenLetter. Javascript doesn't care about that. You could pass it a variable named foobar and it would be fine, or you could just pass it the raw value.
For a simpler example, let's say we had a simple function:
function area (height, width) {
return height * width
}
we could call it in various ways, including:
const height = 5;
const width = 8;
area (height, width) //=> 40
// or
const h = 6
const w = 7
area (h, w) //=> 42
// or
const rectangle = {
height: 3,
width: 10
}
area (rectangle.height, rectangle.width) //=> 30
// or simply
area (4, 9) //=> 36
The same principle applies to handleGuess
in JavaScript
variables that don't get declared will get automatically assigned to the global scope
is simple words it will declare it self :)
in your case something different is happening
you are passing the letter as a parameter to the function
onClick = "handleGuess('` + letter + `')"
and this is why it makes all the magic come alive :)
the same goes to the id property
id = '` + letter + `'
passing the information about which specific letter you are pressing on make it so that the JavaScript Engine know which button is being pressed and that is how it know what letter you chose and what he need to disable
The problem I have is that on every button click, the result of my function, which is an array pushes continuously to a primary array. The most important elements in my HTML page are:
Two input element of the type:number with ids of #firstinput and
#secondinput;
A button with id #submit;
A div to show result with id #result.
I had an idea of refreshing my browser on every click with the use of window.location.reload(), but this does not solve the problem as the result of my work will disappear instantly.
Here is my JavaScript Code:
let scale = [],
submitButton = document.querySelector("#submit");
submitButton.addEventListener("click", weightBalancer);
function weightBalancer() {
let weightsForLeftAndRightSides = document.querySelector("#firstinput").value,
weightsForBalancing = document.querySelector("#secondinput").value;
inputValidator(weightsForLeftAndRightSides, weightsForBalancing);
inputValuesToJson(weightsForLeftAndRightSides, weightsForBalancing);
}
function inputValidator(firstInput, SecondInput) {
if (firstInput == "" || SecondInput == ""
|| isNaN(firstInput) || isNaN(SecondInput)) {
return alert("Enter the require number of digits");
}
if (firstInput < 10 || SecondInput > 99) {
return alert("Enter the require number of digits");
}
if (firstInput < 1000 || SecondInput > 9999) {
return alert("Enter the require number of digits");
}
}
function inputValuesToJson(firstInput, secondinput) {
let firstInputArray = Array.from(firstInput.toString()).map(Number),
secondInputArray = Array.from(secondinput.toString()).map(Number);
scale.push(JSON.stringify(firstInputArray));
scale.push(JSON.stringify(secondInputArray));
//I will remove this later
console.log(scale);
document.getElementById("result").innerHTML = firstInput;
}
I expect to the function to return:
nothing instead of ["[]","[]"] if input elements are empty on
button click;
e.g. ["[]","[]"] and ["[1,2]","[1,4,2,3]"] on two separate button clicks respectively instead of ["[]","[]","[1,2]","[1,4,2,3]"] on the second click.
Thank you.
Having a hard time understanding exactly what you are trying to accomplish but how about doing this instead of pushing to a global variable
function inputValuesToJson(firstInput, secondinput) {
let firstInputArray = Array.from(firstInput.toString()).map(Number),
secondInputArray = Array.from(secondinput.toString()).map(Number);
// scale.push(JSON.stringify(firstInputArray));
// scale.push(JSON.stringify(secondInputArray));
// I will remove this later
const myArray = [ ...JSON.stringify(firstInputArray), ...JSON.stringify(secondInputArray) ]
console.log(myArray);
// return myArray & consume it wherever you want. The array will be reset
// at every call to this function and therefor you will have the expected
// result
document.getElementById("result").innerHTML = firstInput;
return myArray;
}
nothing instead of ["[]","[]"] if input elements are empty on button click;
To Achieve this, all you need to do is run a null check inside your inputValuesToJson function. Add your entire block into a simple if condition.
if (firstInput, secondinput)
{
your content goes here... }
e.g. ["[ ]","[ ]"] and ["[1,2]","[1,4,2,3]"] on two separate button clicks respectively instead of ["[ ]","[ ]","[1,2]","[1,4,2,3]"] on the second click.
You want your array to capture each event click separately, create an array property in the function which is called each time the click event is triggered. Try moving the let scale = [ ] inside your inputValuesToJson() function.
Basically, I want one function to act on multiple elements individually depending on which one is clicked.
I have 3 of these functions that do the same thing:
$("#morelink1, #pic1").click(function() {
var imgHeight = $(".pic").height();
var image = $('#more1').parent('.content').siblings(
'.image');
if ($('#more1').is(":visible")) {
$("#more1").slideUp(200, "linear");
image.height(contHeight);
showtext1();
$("#closemore1").hide();
} else {
$("#more1").slideDown(200, "linear");
image.height(imgHeight);
hidebutton1();
hidetext1();
}
});
As you can see, the names of the IDs I am working with in this function all end in "1." I duplicated this function for 2 and 3.
Instead of duplicating, there must be a way to extract the number from #morelink1, make it a variable, and append the number to the ID in the function.
I'd like to have something like:
var NUMBER = [get the number from the ID of the element that was clicked];
$("#morelink + NUMBER, #pic + NUMBER").click(function() {
I also have functions built into this function - showtext1(), hidebutton1(), and hidetext1(). Those are also duplicated with just the number changed. I'd like to be able to do the same thing with those within this function. Would it be something like showtext(NUMBER)?
I have looked around and can't seem to figure out a way to do this.
Are there other ways to do this, like passing a number to the function?
Instead, just modify your selector to use the "starts with" operator instead of specifying the id completely:
$("[id^='morelink'], [id^='pic']").click(function() {
That would match every element where the id value starts with 'morelink' or 'pic', regardless of what the rest of the id is.
If you still need that value inside the click handler, you can parse it from the id of the current element.
var idString = $(this).attr('id');
// use whatever logic you define to parse the number value.
// for example, maybe a regular expression which matches only numeric characters?
If you could share your whole code, it would help. From my understanding, it should be something along these lines:
// Append click event to elements whose id starts with morelink or pic.
$('[id^="morelink"], id^=["pic"]').click(function() {
// Get id of current clicked element.
var id = $(this).attr('id');
// Use RegExp to extract number.
var number = id.match(/[\d]+/)[0];
// Your functions starting.
var imgHeight = $(".pic").height(); //should this be pic + NUMBER?
var image = $('#more' + number).parent('.content').siblings('.image');
if ($('#more' + number).is(":visible")) {
$('#more' + number).slideUp(200, "linear");
image.height(contHeight);
// Executes selectMore1(); if number = 1
window['showtext' + number]();
$("#closemore" + number).hide();
} else {
$("#more" + number).slideDown(200, "linear");
image.height(imgHeight);
// Executes hidebutton1(); if number = 1
window['hidebutton' + number]();
// Executes hidetext1(); if number = 1
window['hidetext' + number]();
}
});
However, I don't think hidebutton1() should exist, but hidebutton(number). That's why I asked for the whole code to really understand what you meant by creating multiple functions at the moment.
If you know the prefix for variable names, suffix with the number(s) you want. Then plug into the jQuery selector. I've done that before, if direct plug in like $(YourNewVariableForID) won't work, then try $("#" + eval(YourNewVariableForID)).
I have for quite some time now been trying to figure out how I can stop my code to print the same quote twice.
Also, when every single object in the array has been printed out, I'd like for it to reset somehow. So that you can browse through the quotes once you've gone through all of them.
This is the essential parts of my code:
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
The printQuote function simply contains information that's accessing information from my array:
var randomObjectNumber = getRandomQuote();
var html = "<p class='quote'>"
+ quotes[randomObjectNumber].quote +
"</p>";
document.getElementById('quote-box').innerHTML = html;
One random object is displayed each time you click the eventListener:
function getRandomQuote () {
var randomObjectNumber = Math.floor(Math.random() * quotes.length );
return randomObjectNumber;
}
I have some ideas on how to do this and I have tried them but without success. I tried giving each object a boolean property but I can't really seem to assign each property a boolean value without messing the printQuote function up.
I also tried assigning the object displayed to a different array but the same problem occurred there.
I feel like there is some concepts around the eventListener that I don't fully understand, because every time I try to manipulate a displayed object I just end up changing every single object.
This is what a typical object in the array looks like by the way:
{quote : "Darkness is merely the absence of light"}
(I also have other properties assigned to the object but i feel like presenting them would be redundant)
If someone could explain, or give me a hint, on how to solve this problem I've been struggling with for some time.
Some hints would be greatly appreciated!
Have a nice day.
Sebastian.
EDIT: All code: https://jsfiddle.net/fusqb7hz/
Basically what you need:
Create a separate array that will store all quotes that you've already used.
Remove quote from initial array.
Check if you still have quotes in initial array, if not, get them back from backup array.
The problem is that you call addEventListener twice:
//Let's developers create multiple eventListeners without being redundant.
function onClicking (printFunction) {
document.getElementById('loadQuote').addEventListener("click", printFunction, false);
}
onClicking(printColor);
onClicking(printQuote);
by calling onClicking twice you make the click happen twice, so addEventListener is added twice, meaning one click counts as two.
Change the above code for this:
//Let's developers create multiple eventListeners without being redundant.
document.getElementById('loadQuote').addEventListener("click", function(){
printColor();
printQuote();
});
Here is the jsfiddle:
https://jsfiddle.net/fusqb7hz/3/
I think the easiest approach is to shuffle your quote array and then go through them one by one. This gives you the next "random" as yet unseen quote. The only part I'm not keen on is this shuffler (a derivation of Fisher Yates) modifies the original quote array. You might not care about that though.
// --------------------------------
// A bunch of quotes
// --------------------------------
var quotes = [];
quotes.push({quote : "Darkness is merely the absence of light"});
quotes.push({quote : "quote 2"});
quotes.push({quote : "quote 3"});
quotes.push({quote : "quote 4"});
quotes.push({quote : "quote 5"});
// --------------------------------
// --------------------------------
// Your favorite array shuffle utility
// --------------------------------
var shuffle = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};
// --------------------------------
// --------------------------------
// construct a function to get a random unseen quote until
// all quotes have been seen. Then reset...
// --------------------------------
var getQuote = (function(quotes, shuffle){
var current = 0;
var get = function(){
if ( !quotes || !quotes.length ) { return ""; }
if ( current >= quotes.length ){ current = 0; }
if ( current === 0 ){
console.log("randomizing quotes...");
shuffle(quotes);
}
return quotes[current++].quote;
};
return get;
})(quotes, shuffle);
// --------------------------------
var printQuote = function(){
document.getElementById('quote').innerText = getQuote();
};
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
<div id="quote"></div>
<button id="loadQuote">get quote</button>
Let's say I have a dynamic array that is populated on page load with various amounts of strings inside:
var arr = ["string1","string2","string3","string4","string5","string6","string7","string8","string9","string10","string11","string12","string13","string14","string15","string16","string17","string18"];
I then have a function that is called on each event (let's say a click) that needs to bring back 3 strings of the array consecutively while remembering which value it left off at, the last time it was called. So:
First time function is called, it returns:
string1, string2, string3
Second time it is called, it returns:
string4, string5, string6
and so on...
I don't the need the code for the click event or the callback function, rather the code for the function that would generate the extraction each time and bring it back. Something simple like being able to call:
arr.runExtraction();
on each callback and having it bring back the desired data.
What should happen if the array is exhausted? Start from the beginning?
You could do something like this:
function get_iterator(values, steps, start) {
steps = steps || 1;
var current = start || 0,
max = values.length;
return function() {
var end = current+steps,
end = end > max ? max : end,
t = values.slice(current, end);
current = end % max;
// or if you don't want to wrap around:
// current = end;
return t;
}
}
Edit: Added start parameter.
As current will be the same as values.length in the end, splice will return an empty array if you don't wrap around.
Using slice won't change the original array.
And then
var extract = get_iterator(arr, 3);
var arr1 = extract(); // gives you the first three elements
var arr2 = extract(); // gives you the next three elements etc.
DEMO
It might give you less elements in the "last" extraction if the number of elements is not divisible by number of extracted elements. The next call will let it start from the beginning again. You could also modify it that it wraps around and takes elements from the beginning so that it will always return as many elements as you have specified.
Reference: Array.prototype.slice
var arr = ["string1","string2","string3","string4","string5","string6","string7","string8","string9","string10","string11","string12","string13","string14","string15","string16","string17","string18"];
var runExtraction = function () {
return arr.splice(0, 3);
}