function showQuestion(questionAndAnswers) {
const shuffledAnswers = _.shuffle(questionAndAnswers.answers);
questionTag.innerText = questionAndAnswers.question;
shuffledAnswers.forEach(({ text, correct }, i) => {
answerTag[i].innerText = text;
answerTag[i].dataset.correct = correct;
});
}
document.querySelectorAll(".answer").forEach((answer) => {
answer.addEventListener("click", (event) => {
if (event.target.dataset ) {
answer.style.border = "1.5px solid"
}
});
});
function nextQuestion() {
const nextIndex = currentQuestionIndex + 1;
if (nextIndex <= myQuestions.length - 1) {
showQuestion(myQuestions[nextIndex]);
currentQuestionIndex = nextIndex;
} else {
end.style.visibility = "visible";
nxt_question_btn.style.visibility = "hidden";
}
}
Basically, In this quiz app, I have 4 buttons for answers and once you click on one answer it makes the border black. The problem I am facing is that once I press the next question, it loads up another question with 4 different answers but one of the buttons will still have the border black. How do I get it to reset once I load up another question? and Extra question if it's okay, how can I only select one button at a time per question?
There is no 'reset' as there is no default, you will just have to manually undo what you did earlier, i.e to remove the border completely:
answer.style.border = "none";
To select each button individually, you will ave to give them each an ID, based of something like an iteration, instead of trying to select them by the shared class
that's a tough one, there is no easy answer without knowing what the previous style was, so it's good to store the previous value of the style in memory and reset the styles to the previous value after the next question has been loaded
// a variable declared somewhere in common scope
let prevBorder
// "backup" the old value when you want to mark the answer as "selected"
prevBorder = element.styles.border
// restore to the initial value when you want to reset the styles
element.styles.border = prevBorder
Maybe you are looking for css:initial property?
The initial CSS keyword applies the initial (or default) value of a property to an element. It can be applied to any CSS property. This includes the CSS shorthand all, with which initial can be used to restore all CSS properties to their initial state.
Or you could add class and use classList.toggle() to switch between them.
I don't have your html code and full code so can't help you fully, but this is an example that may help you implement to your code:
document.querySelectorAll('button').forEach(item => {
item.addEventListener('click', function() {
item.style.border = '10px solid black'
document.querySelectorAll('button').forEach(i => {
if (i != item)
i.style.border = "initial"
})
})
})
<button>Click</button>
<button>Click</button>
<button>Click</button>
<button>Click</button>
Related
I want to reset the game by appending child element back to '1'. By default in html it is labelled as 1 and on finishing game it gets to empty but when this bonus life is used i want at the end of the game to be reset to '1'.
<h2>PLAYER HEALTH<span id="bonus-life">1</span></h2>
I have used this function in JavaScript but seem to be not working:
function resetBonus() {
bonusLifeEl.parentNode.appendChild(bonusLifeEl);
}
This function is called in a file which is like this:
if (currentMonsterHealth <= 0 || currentPlayerHealth <= 0) {
reset();
resetBonus();
}
Reset function just remove bonus life
function reset() {
currentMonsterHealth = chosenMaxLife;
currentPlayerHealth = chosenMaxLife;
resetGame(chosenMaxLife);
}
Nothing will be changed when you try to add a child to the parent where it is already exists.
You can change the value instead of add/remove child by innerText or innerHTML values.
function resetBonus() {
bonusLifeEl.innerHTML = bonusLifeEl;
}
my demo jsfiddle
What I want is a reverse transition when I click the < li > again, but the commentted code didn`t work,and the code below works fine
let dbclickre = true;
function flipped() {
if (dbclickre) {
document.querySelector(".linkrec").setAttribute("Id", "flipped");
} else {
document.querySelector(".linkrec").removeAttribute("Id", "flipped")
}
dbclickre = !dbclickre;
}
below is the commentted code (I think when i firstly click the last < li > ,js will excute the if statement(and indeed it works fine),but when i click again , the else statement didn't excude(but i have set #flipped .reverse {background: whitesmoke} ) . why this happening???)
// const dbclickre = document.querySelector(".reverse");
// function flipped() {
// if (dbclickre.style.backgroundColor = 'white') {
// document.querySelector(".linkrec").setAttribute("Id", "flipped");
// } else {
// document.querySelector(".linkrec").removeAttribute("Id", "flipped")
// }
// }
Instead of relying on background color for checking the state of flip, you could check for existence of Id attribute. Here the the changed code:
const dbclickre = document.querySelector(".reverse");
function flipped() {
if ( document.querySelector(".linkrec").getAttribute("Id") == undefined ) {
document.querySelector(".linkrec").setAttribute("Id", "flipped");
} else {
document.querySelector(".linkrec").removeAttribute("Id", "flipped")
}
}
Edit:
Why element.style would not work?
From MDN Web Docs:
The style property is used to get as well as set the inline style of an element.
Hence, the style property would not work with embedded or external CSS.
Also, it may not be a good idea to use hard-coded colors as the condition, because changing colors in the respective CSS classes would completely break the functionality.
I'm making a hangman game using JavaScript and need to hide some HTML for a few seconds to display an error message, and then revert back to the original HTML. I've tried using setTimeout(); and setInterval(); but those seem to just wait a few seconds before displaying the error message.
Here's the code for reference:
<div class="row text-center">
<div id="alredGuess" class="col">
<div>
<span id="guessedLetters"></span> <br>
</div>
<div>Guesses left:<span id="guessesLeft">10</span></div>
<div>Wins:<span id="wins">0</span></div>
<div>Losses:<span id="losses">0</span></div>
</div>
</div>
JS:
if (gameRunning === true && guessedLetterBank.indexOf(letter) === -1) {
// run game logic
guessedLetterBank.push(letter);
// Check if letter is in picked word
for (var i = 0; i < pickedWord.length; i++) {
//convert to lower case
if (pickedWord[i].toLowerCase() === letter.toLowerCase()) {
//if match, swap placeholder
pickedWordPlaceholderArr[i] = pickedWord[i];
}
}
$placeholders.textContent = pickedWordPlaceholderArr.join("");
checkIncorrect(letter);
} else if (gameRunning === false) {
$placeholders.textContent = "Press \"A\" To Begin!"
} else {
//alert("You've already guessed this letter.")
function newAlert() {
var hideDiv = document.getElementById("alredGuess");
if (hideDiv.style.display = "block") {
hideDiv.style.display = "none";
}
}
hideDiv.textContent("You've already guessed this letter!");
function showDiv() {
var showDiv = document.getElementById("alredGuess");
if (hideDiv.style.display = "none") {
hideDiv.style.display = "block";
}
}
}
}
setInterval(newAlert, 3000);
}
Tip 1
Well, first of all i don't recommend using display: block|none to show or hide DOM elements. Instead try using visibility: visible|hidden or better, toggle a css class name such as : .hidden. That's because when you set a DOM element's display to none, its width and height are gonna be set to zero, often causing an unwanted loss of space because the DOM node visually collapses. With the visibility property, for example, the element just disappears without loss of space.
Tip 2
Error/status messages should always live within their own containers. Do not display messages in substitution of some content you need to revert back after.
It is always better to prepare an empty <div>, hide it by default with a generic .hiddenCSS class and then remove this one as soon as you need to display the container.
Suggested solution
Now, in your case, i think you're using setIntervalin the wrong way. You have to immediately show the alert message, then make it disappear after a few seconds.
As suggested above, this should be done by toggling CSS classes, using different containers and using setTimeout in order to remove/add the CSS classes as soon as the interval is over. Basically, the setTimeout restores everything to its original state.
So, given this HTML code:
<div id="alredGuess">This is the original text</div>
<div id="alertbox" class="hidden"></div>
and this CSS code:
.hidden { visibility: hidden; }
try this:
var alertTimeout = 1000; // Timeout in milliseconds.
function showAlertMessage() {
// This is your original text container.
var alredGuess = document.getElementById("alredGuess");
// This is the new error message container named #alertbox
var alertBox = document.getElementById("alertbox");
// Now let's fill it with the specific error text (better using HTML here).
alertBox.innerHTML = "You've already guessed this letter!";
// Hide the original container by adding an .hidden css class.
alredGuess.classList.add('hidden');
// Show the error message container by removing its default .hidden css class.
alertBox.classList.remove('hidden');
// Then set up an interval: as it ends, revert everything to its original state.
setTimeout(function() {
alertBox.classList.add('hidden');
alredGuess.classList.remove('hidden');
}, alertTimeout);
}
// Call the function.
showAlertMessage();
Fiddle: https://jsfiddle.net/qyk4jspd/
Hope this helps.
froI have a form with many inputs and I want to add a class to focused input label tag and remove class when another input selected.
I make such code
onInputSelected: function(e) {
var label = e.target.previousElementSibling;
label.classList.add('highlight');
}
but how can I remove class from one input and add to another when I change focus?
Updated:
I found solution but looks like it's to complicated :)
data: {
allInputs: document.getElementsByTagName('input')
},
methods: {
onInputSelected: function(e) {
e.target.previousElementSibling.classList.add('highlight');
[].forEach.call(this.allInputs, function (currentValue, index) {
if(currentValue.name == this.name) {
return;
}
currentValue.previousElementSibling.classList.remove('highlight');
}, e.target);
}
}
First of all you're not being very clear what you want to do.
2nd of all you have found solution so just clean up your code.
3rd of all I'd try using el.closest.
const input = document.getElementById('yourInput');
const label = input.closest("label");
// or if you want to add ids to labels
const label2 = input.closest("#yourLabel");
Link to docs
With this solution you will be little bit more save. Couse in yours, lets just imagine that somebody change HTML structure... Then very high risk your code stops working.
hey guys having trouble figuring out how to make it so that i can make it only open one table at once, once you open another the other should close any help here?
function showRow(cctab){
if (document.getElementById(cctab)) {
document.getElementById(cctab).style.display = '';
}
}
function hideRow(row1){
if (document.getElementById(cctab)) {
document.getElementById(cctab).style.display = 'none';
}
}
function toggleRow(cctab){
if (document.getElementById(cctab)) {
if (document.getElementById(cctab).style.display == 'none') {
showRow(cctab)
} else {
hideRow(cctab)
}
}
}
Now I want to make it so that only one table "cctab" opens after I suggest the onClick="javascript:toggleRow(cctab);" anyhelp?
Well you could save a reference to the previously shown item and hide it when another is shown:
var currentTab;
function showRow(cctab){
if (document.getElementById(cctab))
document.getElementById(cctab).style.display = '';
if (currentTab && currentTab != cctab)
hideRow(currentTab);
currentTab = cctab;
}
Note that doing inline event handler attributes is so 1999, but assuming you're sticking with it for whatever reason you don't need the javascript: in onClick="javascript:toggleRow(cctab);". (Just say onClick="toggleRow(cctab);")
First you need to store the old row somewhere.
What you've got is a system where you're using <element onclick="..."> to pass the id of the current element into the controller that shows or hides the row.
But if you look at that, what you're missing is a way of telling what the last open row was.
So what your code will need is a central object, or variables which store the old element and the new element.
How you do this is up to you, but if you did something like this:
var table_rows = { current : null /* or set a default */, previous : null };
function rowController (cctab) {
var newRow = document.getElementById(cctab);
if (newRow === table_rows.current) { toggleRow(newRow); }
else {
table_rows.previous = table_rows.current;
table_rows.current = newRow;
showRow(table_rows.current);
hideRow(table_rows.previous);
}
}
Note:
This deals with elements directly, so you don't have to do getById in your functions;
that's handled one time, and then that element is passed around and saved and checked against.
It assumes that the click is happening on the row itself, and not on anything inside of the row;
that's a separate issue that your code has.
Unless it's obvious and easy to click on the row, and not the cells inside of the row, it's difficult to tell how you want users to be able to open and close rows.
What I mean is if only the table-row has an onclick, and somebody clicks on a table-column, then then onclick isn't going to fire.