I am creating a quiz for my webpage. Currently, I have a function working on the first question. Where a button will say "Show Solution". Once clicked, it will show the element. Currently the button doesn't change the button text to "Hide Solution" once it has been displayed.
The main problem is that i have multiple questions. And when i click show solution it will show the first question.
I know that the function is linked to that function, but I do not want to copy the function multiple times and change the IDs to answer1, answer2 etc...
I have looked at posts on google/stack and YouTube videos and I just don't understand it really.
Here is my code
function show_hide()
{
var myAnswer = document.getElementById('answer');
var displaySetting = myAnswer.style.display;
var quizButton = document.getElementsByClassName('quiz-button');
if(displaySetting=="inline-block"){
myAnswer.style.display = 'none';
quizButton.innerHTML = 'Show Answer';
}
else
{
myAnswer.style.display = 'inline-block';
quizButton.innerHTML = 'Hide Answer';
}
}
.quiz-question{
margin-bottom: 10px;
text-align: left;
font-size: 15px;
color: #f44336;
font-weight: 400;
}
.quiz-button{
display: inline-block;
text-decoration: none;
color: #111;
border: 1px solid #f44336;
padding: 5px 5px;
font-size: 13px;
background: transparent;
position: relative;
cursor: pointer;
}
.quiz-button:hover{
color: #fff;
background: #f44336;
transition: 0.5s;
}
#answer{
display: none;
}
<div class="part-content quiz">
<h2>Chapter 1.1 End of Topic Quiz</h2>
<p>
The following quiz is meant to reinforce your understanding of the material presented above.
</p>
<!-- Question 1 Start -->
<h4 class="quiz-question">1. What is a statement? </h4>
<button onclick="show_hide()" class="quiz-button">Show Solution</button>
<p id="answer">
A <b>statement</b> is an instruction in a computer program that tells the computer to perform an action.
</p>
<br><br><hr>
<!-- Question 1 End -->
<!-- Question 2 Start -->
<h4 class="quiz-question">2. What is a function? </h4>
<button onclick="show_hide()" class="quiz-button">Show Solution</button>
<p id="answer">
A <b>function</b> is several statements that are executed sequentially.
</p>
<br><br><hr>
</div>
Here is one of the easiest solutions:
Change all onclick="show_hide()" to onclick="show_hide(this)"
Change your JS to:
<script>
function show_hide(element)
{
var myAnswer = element.nextElementSibling;
var displaySetting = myAnswer.style.display;
var quizButton = element;
if(displaySetting=="inline-block"){
myAnswer.style.display = 'none';
quizButton.innerHTML = 'Show Answer';
}
else
{
myAnswer.style.display = 'inline-block';
quizButton.innerHTML = 'Hide Answer';
}
}
</script>
With this, you won't need to refer to the answer's ID anymore.
The "this" in the onclick attribute is referring to the button itself, and the "nextElementSibling" refers to the next element (which is the containing the answer in your case) of the element (button). So actually var myAnswer means to get the next element of the button.
However, with this function, you need to make sure the button's next element is the answer element, else won't be working.
Also, the reason why directly var quizButton = document.getElementsByClassName('quiz-button'); won't work is because as you see, it gets multiple elements instead of one element. Different elements can have the same class. This will return an array of the elements having the class instead of the first element having the class.
Related
I'm working on a project where subscribers to a site can choose between a monthly and yearly subscription. The user has to choose their subscription type by clicking on a monthly or yearly button (Button code below)
<!-- Select Subscription Instructions -->
<p class="mb-0">
<strong>Select your subscription type then click subscribe:</strong>
</p>
<!-- Yearly Subscription Button -->
<button id="yearly_subscription_selected" class="btn mr-2" type="submit" onclick="">
Yearly Membership: £41.50 plus VAT
</button>
<!-- Monthly Subscription Button -->
<button id="monthly_subscription_selected" class="btn my-2" type="submit" onclick="">
Monthly Membership: £8.25 plus VAT
</button>
When the user clicks on one of these buttons the href="" behind the subscribe button will change (This is working correctly)
I also want the membership button the user clicks on to change the background colour while the unselected membership button remains white. I have used the following JS code for this:
// Membership select Year JS
document.getElementById("yearly_subscription_selected").onclick = function () {
let link = document.getElementById("abc");
link.setAttribute("href", "https://www.checkouty.htm");
document.getElementById("yearly_subscription_selected").setAttribute("style", "background-color: green; color: #fff");
if (document.getElementById("yearly_subscription_selected").style.backgroundColor == "green") {
document.getElementById("monthly_subscription_selected").setAttribute("style", "background-color: white; color: #000");
}
return false;
}
// Membership select Month JS
document.getElementById("monthly_subscription_selected").onclick = function () {
let link = document.getElementById("abc");
link.setAttribute("href", "https://www.checkoutm.htm");
document.getElementById("monthly_subscription_selected").setAttribute("style", "background-color: green; color: #fff");
if (document.getElementById("monthly_subscription_selected").style.backgroundColor == "green") {
document.getElementById("yearly_subscription_selected").setAttribute("style", "background-color: white; color: #000");
}
return false;
}
This code above is working and when the user selects a membership option the selected option button will turn green and the none selected button will turn white. However, if I change the background-color: "green"; and replace it with the hex colour code background-color: #bf1363 then the JS stops working and when you click on both buttons to switch between the memberships both buttons turn the same colour #bf1363.
// Membership select Year JS
document.getElementById("yearly_subscription_selected").onclick = function () {
let link = document.getElementById("abc");
link.setAttribute("href", "https://www.checkouty.htm");
document.getElementById("yearly_subscription_selected").setAttribute("style", "background-color: #bf1363; color: #fff");
if (document.getElementById("yearly_subscription_selected").style.backgroundColor == "#bf1363") {
document.getElementById("monthly_subscription_selected").setAttribute("style", "background-color: white; color: #000");
}
return false;
}
// Membership select Month JS
document.getElementById("monthly_subscription_selected").onclick = function () {
let link = document.getElementById("abc");
link.setAttribute("href", "https://www.checkoutm.htm");
document.getElementById("monthly_subscription_selected").setAttribute("style", "background-color: #bf1363; color: #fff");
if (document.getElementById("monthly_subscription_selected").style.backgroundColor == "#bf1363") {
document.getElementById("yearly_subscription_selected").setAttribute("style", "background-color: white; color: #000");
}
return false;
}
Does anyone know why this might be happening?? I'm using bootstrap 4 and vanilla JS
Because when you do:
document.getElementById("yearly_subscription_selected").style.backgroundColor = "#bf1363";
console.log(document.getElementById("yearly_subscription_selected").style.backgroundColor);
It will return:
rgb(191, 19, 99)
So you can't compare that value with your string #bf1363 that's just one of the many ways to encode a color value.
Refactor
Anyway since your code had so many repetitions and was directly changing the element style instead of using css classes, I took the chance to better refactor your code to show that the same result could be achieved differently.
Here you have two css classes btn-subscription and active. The first is styling the button when it still isn't active (white bg) and the second one will style the button as active (purple bg).
Plus each of those buttons store the url where the link is supposed to point at as a data-url attribute.
That way you can have a single event handler that will deal with the click event occurring on both the buttons:
let link = document.getElementById("abc");
//selects all the `.btn-subscription` elements
document.querySelectorAll('.btn-subscription')
//for each one of them as btn
.forEach( btn => {
//adds the click event handler
btn.addEventListener('click', (event)=>{
//the currently clicked button
const clickedButton = event.target;
//changes the href attribute of link as the data-url of the currently clicked btn
link.setAttribute("href", clickedButton.dataset.url);
//removes the active class from the first element .btn-subscription having it (if any)
document.querySelector('.btn-subscription.active')?.classList.remove('active');
//adds the class active only to the currently clicked button
clickedButton.classList.add('active');
});
});
#abc{
display: block;
margin-top: 2rem;
border: solid;
padding: 1em;
}
/*just to show on screen the href attribute value*/
#abc::before{
border: dashed 3px lightgray;
content: "href: " attr(href);
display: block;
padding: 4px .5em;
margin-bottom: 1em;
}
.btn-subscription{
cursor: pointer;
background-color: white;
color: #000;
}
.active{
background-color: #bf1363;
color: #fff;
}
<!-- Select Subscription Instructions -->
<p class="mb-0">
<strong>Select your subscription type then click subscribe:</strong>
</p>
<!-- Yearly Subscription Button -->
<button
id="yearly_subscription_selected"
class="btn mr-2 btn-subscription"
type="button"
data-url="https://www.checkouty.htm">
Yearly Membership: £41.50 plus VAT
</button>
<!-- Monthly Subscription Button -->
<button
id="monthly_subscription_selected"
class="btn my-2 btn-subscription"
type="button"
data-url="https://www.checkoutm.htm">
Monthly Membership: £8.25 plus VAT
</button>
<a id="abc" href="">Link target element</a>
I'm trying to make a window that slide up when the X button(close.png) is clicked.
I added the Wrap element with JavaScript, and added an img element inside.
Then, I put following JavaScript, but there is no change when I press the X button.
<script>
const parent3 = document.querySelector('#wrap');
const billingField3 = document.querySelector('#woocommerce-input-wrapper');
const newImg = document.createElement('img');
newImg.setAttribute("src", "//t1.daumcdn.net/postcode/resource/images/close.png");
newImg.setAttribute('id', 'btnFoldWrap');
newImg.style.cssText = 'cursor:pointer;position:absolute;right:0px;top:-1px;z-index:1';
newImg.onclick = "offDaumZipAddress();"
parent3.insertBefore(newImg, billingField3);
</script>
function offDaumZipAddress() {
jQuery("#wrap").slideUp();
}
Website structure is
<div class="woocommerce-billing-fields__field-wrapper">
<p class="billing_postcode_find_field">..
<span class="woocommerce-input-wrapper">...
</span>
</p>
<div id="wrap" ..>
<img src="..."></img>
</div>
<p class="billing_address_1_field">
<span class="woocommerce-input-wrapper">
Checking with the console of chrome developer tools doesn't show any errors.
Could someone please let me know what am I missing?
Thank you.
The value of the onclick property must be a function reference, not a JavaScript string.
newImg.onclick = offDaumZipAddress;
You have your answer; here is a working example of that loosely based on your code (so the inserted image actually shows, added some CSS etc. to illustrate)
//gets first one of this type
const billingField3 = document.querySelector('.woocommerce-input-wrapper');
// Get a reference to the parent node/ gets first one of this type
const parent3 = billingField3.parentNode;
//console.log(parent3);
//console.log(billingField3);
// Create the new node to insert
const newImg = document.createElement('img');
newImg.setAttribute("src", "//t1.daumcdn.net/postcode/resource/images/close.png");
newImg.setAttribute('id', 'btnFoldWrap');
newImg.setAttribute('alt', 'folderWrap');
// no not this: newImg.style.cssText = 'cursor:pointer;position:absolute;right:0px;top:-1px;z-index:1';
// this:
newImg.classList.add("inserted-image");
newImg.onclick = offDaumZipAddress;
//console.log("Thing:",newImg);
//console.log("HTML:", parent3.innerHTML);
parent3.insertBefore(newImg, billingField3);
//console.log("New HTML:", parent3.innerHTML);
function offDaumZipAddress() {
console.log('here we go');
jQuery("#wrap").slideUp();
}
.billing_postcode_find_field {
border: solid blue 1px;
padding: 1rem;
}
.woocommerce-input-wrapper {
border: solid 1px lime;
padding: 1rem;
}
.inserted-image {
cursor: pointer;
/* This is odd, makes it not clickable:
position: absolute;
right: 0px;
top: -1px;
z-index: 1;*/
border: solid 1px red;
min-width: 1.5rem;
min-height: 1.5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="woocommerce-billing-fields__field-wrapper">
<p class="billing_postcode_find_field">..
<span class="woocommerce-input-wrapper">...</span>
</p>
<div id="wrap">
<img src="//t1.daumcdn.net/postcode/resource/images/close.png" alt="png"></img>
</div>
<p class="billing_address_1_field">
<span class="woocommerce-input-wrapper"></span>
</div>
Here's the parent div:
<div
id="comment"
placeholder="Your comment"
class="form-control ellipsesDropdown"
contenteditable="true"
#input="CommentChanged($event)"
> <!-- comments are divided into spans and divs with spans containg normal text and divs containing tags -->
<span></span>
</div>
Now when a user clicks a Tag, I create the Tag as follows:
const newTag = document.createElement('div');
newTag.setAttribute("tabindex", "-1");
newTag.style.cssText = "background-color: rgba(29,155,209,0.1); color: #1264a3; display: inline-block; font-weight: bold;";
const tagContent = document.createTextNode(`#${p}`); // imagine p is an input argument
newTag.append(tagContent);
// attach on key down event listener
newTag.onkeydown = function(event) {
console.log(event)
};
// add tag to the comment div
document.getElementById("comment")!.appendChild(newTag);
However, I get nothing when I press keys in the tag div, click events do work though. I took a look at How can I use a 'keydown' event listener on a div? and have added the tabindex attribute.
I've also tried attaching the event listener as:
newTag.addEventListener('keydown', function(event) {
console.log(event);
});
But this still doesn't work.
Any idea about what's going on?
EDIT: As requested, here's a codesandbox link: https://codesandbox.io/s/blue-bird-tdidr
EDIT 2: I've added more code from my project that basically implements to a certain extent what I'm trying to accomplish. Think about Twitter/Instagram/Slack, when you #someone as you're typing the post then perhaps some options appear for who to # and when you click someone then that "tag" is added to your post. In the example, go ahead and write something, and include #, you'll see a list of options open, click either bread or toast and see it become a tag. What I'm trying to do it add the on keydown EventListener on the Tag so go ahead and see that it doesn't work!
I see you want to create a comment function i guess? But the way you do its not the Vue.js way. Here is a simple comment box example:
let el = new Vue({
el: "#app",
template: "",
data(){
return {
comment: "",
comments: []
}
},
methods: {
addComment(){
let txt = this.convertTags(this.comment);
console.log(txt);
var d = new Date();
var n = d.toLocaleTimeString();
this.comments.push({
commentText: txt,
time: n
});
this.comment = "";
},
clickedTag(tag){
console.log(tag);
},
convertTags(str){
let strArr = str.split(" ");
let mappedArr = strArr.map(el => {
if(el.includes("#")){
el = `<span onclick='el.clickedTag("${el.replace("#", "")}")' class='tag'>${el}</span>`;
}
return " " +el;
});
this.template = mappedArr.join("")
return this.template;
}
}
});
#app {
width: 80%;
margin: 0 auto;
}
.comment {
background: #6c5ce7;
width: 100%;
margin: 5px 0;
color: white;
padding: 8px 5px;
}
input {
margin: 0 auto;
width: 100%;
display: block;
padding: 5px;
}
.tag {
color: black;
background: white;
padding: 2px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="comment in comments" class="comments">
<div class="comment">
<p v-html="comment.commentText"></p>
<small>{{ comment.time }}</small>
</div>
</div>
<input type="text" v-model="comment" #keyup.enter="addComment">
</div>
Apparently I don't need to add an event listener to the divs I'm adding. I can just set their contenteditable attribute to false as user SleepWalker menstions in his answer here: How to delete an HTML element inside a div with attribute contentEditable?
So my answer would then become:
...
newTag.setAttribute("contenteditable", "false")
document.getElementById("comment")!.appendChild(newTag);
This allows me to delete the tag in one go!
Here is the important part of the code that executes.
Im trying to click on one element with a particular ID that relates to bookmarking the message but the element keeps triggering another click event that hides every div with the class 'messageCase' while at the same time attaching class messageOpen2 to the bookmark images ID which is very odd
the 'hidden' classes just hide all other message instances that contain
The messageCase class.
var openMessageAnimationStrategy = function () {
var openMessage = $(document).ready(function () {
var divTarget = $("div.messageCase");
$(divTarget).click(function (e) {
var target = $(e.target);
target.toggleClass('messageOpen2');
divTarget.addClass('hidden');
target.removeClass('hidden');
});
});
};
Here is what the HTML looks like
<div class="messageCase">
<div class="messageImageBox">
<div id="messageImage">
</div>
</div>
<div id="subjectLine">
Subject Line Text
</div>
<div id="bookMarkImage">
<img id="bookmarkStatus" class="savedMessage" src="notbookMarked64.png" />
</div>
<div class="activeBookmarks">
{38} <br />
Bookmarks <br />
<br />
9:53am
</div>
<div id="bodyPreview">
Body Preview Text is light
</div>
</div>
Every Time I use the Click event on bookmarkStatus to change the src of the image it causes the first click event to execute making everything disappear & the class messageOpen2 to be added to bookmarkStatus. I can include the CSS if necessary but ill list the code for the bookmarking function below
var bookmarkedStrategy = function () {
var bookmarkedStrategy = $(document).ready(function () {
var bookmarkStatus = $("#bookmarkStatus");
var divTarget = $('messageCase');
//below trying to remove the Class that was attached by the initial function while also changing the image SRC for the class bookmark
$(divTarget).click(function (e) {
var target = $(e.target);
divTarget.removeClass('messageCase2');
bookmarkStatus.toggleClass('savedMessage');
});
});
};
I Think the main problem has to do with the initial function but I don't know what else could be wrong any ideas?
edit Here is the CSS that matters.
.savedMessage {
background-image: url("bookmarked64.png");
}
.messageOpen2 {
height: 250px;
}
.messageCase {
margin: 5px;
border-radius: 5px;
background-color: aliceblue;
height: 70px;
}
#bookMarkImage {
float:right;
height:64px;
width:64px;
z-index:9999;
}
.hidden {
display:none;
max-height: inherit;
}
.activeBookmarks {
float: right;
text-align: center;
font-size: 13px;
font-weight: 700;
text-decoration: solid;
}
Calling code
var bookmarkedthings = new MessageHandling(bookmarkedStrategy);
bookmarkedthings.greet();
var openMessage = new MessageHandling(openMessageAnimationStrategy);
openMessage.greet();
There is a missing . in your bookmarkedStrategy function code var divTarget = $('.messageCase'); Add dot and try again
What I want to do in Javascript/Jquery is be able to click a button (a button on each item), that adds it to an array. This array will then be posted in order when you click on a favorites page.
I'm just having a hard time wrapping my head around how this would work. Because I may want each item in the array to contain a few things, such as a picture and text describing the item.
In general terms/examples, how would this be set up?
There are a number of ways to do this. But, I'll go with one that's a bit more general - which you can extend for yourself:
http://jsfiddle.net/TEELr/11/
HTML:
This simply creates different elements with the favorite class - which will be the selector by which we check if an element has been clicked.
<div class="favorite"><p>Add to favorites</p></div>
<div class="favorite type2"><p>Just another favorite type</p></div>
<button id="reveal">
Reveal Favorites
</button>
JS:
Every time an element with the "favorite" CSS class is clicked, it is added to the array - this also works for elements with more than one class (that have the "favorite" CSS class).
Now, when the "Reveal Favorites" button is clicked, it will alert what's in the array - which is in the order clicked (as asked).
$(document).ready(function() {
var favorites = [];
var counter = 0;
$('.favorite').click(function() {
++counter;
favorites.push("\"" + $(this).text() + " " + counter + "\"");
});
$('#reveal').click(function() {
alert(favorites);
});
});
CSS:
Simple CSS that only exist for demonstration purposes to prove previous point with multiple CSS class selectors:
.favorite {
width: 400px;
height: 50px;
line-height: 50px;
text-align: center;
display: block;
background-color: #f3f3f3;
border-bottom: 1px solid #ccc;
}
.favorite.type2 {
background-color: #ff3;
}
.favorite:hover {
cursor:hand;
cursor: pointer;
}