Custom / Styled prompt window? - javascript

I'm trying to make a 'Choose your Adventure' game, and I want to know if it's possible to make a styled/custom 'Prompt' window, and if it can be not opened up as a 'prompt' window, but have the prompt and user input in a selected HTML box? This is what I mean.
If my HTML has
HTML
<html>
<body>
<textarea class="prompt" disabled="1"></textarea><br>
<input class="input" type="text" value="inputText"></input>
<input type="submit" value="userInput"></input>
</body>
</html>
and CSS of
CSS
.prompt {
width: 300px;
height: 500px;
background: black;
color: #FFA500;
}
and JavaScript (I probably will mess up the code)
JavaScript
var prompt = document.getElementByClassName("prompt");
var choice = prompt("What is your choice? CHOICE1, CHOICE2, or CHOICE3?").toUpperCase();
prompt.innerHTML = choice;
and I hope to get something like the prompt not showing up a dialogue window but instead putting the prompt text into the textarea, and the user put in their choice with the input, then submit it by the submit button. How could I get it so that the prompt window instead outputs the question/text to the textarea, and the user puts in their answer via the input text field, and submitting it via the input submit button, and it works like normal. Is this even possible?
If not, is it at least possible to style the prompt dialogue box itself? Here's my code so far.
function fight() {
var intro = prompt("You are a hero who saved your town from a dragon attack years ago. You had fun murdering that dragon, but sadly no dragon has attacked since. Just when all hope is lo, you hear the sirens ring through the city. You know what that means. Do you PREPARE, or IGNORE THE SIRENS?").toUpperCase();
switch(intro) {
case 'PREPARE':
if(intro === "PREPARE") {
prompt("You decided to " + intro + ". You need to choose what you will do. Keep in mind, the more activities you do, the less energy you have! You only have 3 days to prepare! What do you do? Do you SEARCH ARMOR STAND, SEARCH WEAPON STAND, GO TO MERCHANT, FIGHT DRAGON, TRAIN, or SLEEP?").toUpperCase();
}
}
}
#import url(http://fonts.googleapis.com/css?family=Permanent+Marker);
html, body {
background: #000;
margin: 0;
padding: 0;
}
#wrap {
width: 760px;
margin-left: auto;
margin-right: auto;
}
.container {
position: relative;
top: 50px;
margin-left: auto;
margin-right: auto;
width: 570px;
height: 350px;
border: 6px ridge orange;
padding: 0;
}
.container img {
position: absolute;
bottom: 0px;
width: 570px;
height: 350px;
z-index: -1;
}
p.intro {
color: black;
text-shadow:
-1px -1px 0 #FFF,
1px -1px 0 #FFF,
-1px 1px 0 #FFF,
1px 1px 0 #FFF;
}
h2.header {
text-shadow:
-1px -1px 0 #FFA500,
1px -1px 0 #FFA500,
-1px 1px 0 #FFA500,
1px 1px 0 #FFA500;
}
.box {
float: left;
min-width: 567px;
min-height: 350px;
}
.box h2 {
font-family: 'Permanent Marker', cursive;
font-size: 200%;
text-align: center;
}
.box p {
font-family: 'Permanent Marker', arial;
text-align: center;
}
.box a {
position: absolute;
left: 165px;
display: inline-block;
border: 3px groove #000;
border-radius: 5px;
background: red;
margin-left: auto;
margin-right: auto;
width: 225px;
height: 75px;
font-family: 'Permanent Marker', cursive;
color: #FFA500;
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
text-align: center;
}
.battles img {
}
<html>
<body>
<div id="wrap">
<div class="box">
<div class="container">
<h2 class="header">Dragon Slayer - REBORN!</h2>
<p class="intro">You are a hero who saved your town from a dragon attack years ago. You had fun murdering that dragon, but sadly no dragon has attacked since. Just when all hope is lost, you hear the sirens ring through the city. You know what that means.</p>
<br>BEGIN!
<img class="scenario" src="http://www.thegaminghideout.com/school/stage1.png">
<div class="battles">
</div>
</div>
</div>
</div>
</body>
</html>

Here is an example using jQuery. jQuery is useful for manipulating DOM elements. Instead of selecting an object by doing:
document.getElementById('someid');
You would select the element as you would in CSS:
$('#someid);
In my adventure game example, I used a JSON object to contain my story and its paths. The story object is a map of path id (e.g. 'intro', 'choose_weapon') to a scenario object. This helps to organize your story.
I used buttons instead of input fields for the options since making the user input their choices gets pretty annoying.
// Contains the story and paths
var story = {
intro: {
prompt: 'It is 12am and you are starving. It\'s too late to order delivery. You know what that means.',
options: [{
name: 'Fight',
path: 'choose_weapon'
}, {
name: 'Starve',
path: 'die_starve'
}]
},
choose_weapon: {
prompt: 'Choose your weapon!',
options: [{
name: 'Knife',
path: 'die_cut'
}, {
name: 'Toaster',
path: 'toast'
}]
},
toast: {
prompt: 'You toast some bread. What do you do next?',
options: [{
name: 'Eat it!',
path: 'eat'
}, {
name: 'Slather on some peanut butter!',
path: 'peanut_butter'
}]
},
peanut_butter: {
prompt: 'There is now peanut butter on your bread. Excellent choice. What do you do next?',
options: [{
name: 'Eat it!',
path: 'eat'
}, {
name: 'Throw it away',
path: 'die_starve'
}]
},
eat: {
prompt: 'It was delicious! You are no longer hungry.',
options: [{
name: 'Start Again',
path: 'intro'
}]
},
die_cut: {
prompt: 'You accidentally cut yourself and bleed to death.',
options: [{
name: 'Start Again',
path: 'intro'
}]
},
die_starve: {
prompt: 'You have died of hunger!',
options: [{
name: 'Start Again',
path: 'intro'
}]
}
}
/**
* Chosen option is an object with properties {name, path}
*/
function display_scenario(chosen_option) {
var option_name = chosen_option.name;
var option_path = chosen_option.path;
var scenario = story[option_path];
// Clear the #prompt div and the #options div
$('#prompt').empty();
$('#options').empty();
// Create a <p> to display what the user has chosen if option_name is not null and append it to the #prompt <div>
if (option_name) {
$('<p>').html('You have chosen <b>' + option_name + '</b>').appendTo('#prompt');
}
// Append the scenario's prompt
$('<p>').html(scenario.prompt).appendTo('#prompt');
// Append the options into the #options <div>
// We want to loop through all the options and create buttons for each one. A regular for-loop would not suffice because adding a button is not asynchronous. We will create an asynchronous loop by using recursion
function add_option_button(index) {
if (index === scenario.options.length) {
// Base case
return;
}
var option = scenario.options[index];
// Create a <button> for this option and append it to the #options <div>
$('<button>')
.html(option.name)
.click(function(e) {
// This is an onclick handler function. It decides what to do after the user has clicked on the button.
// First, prevent any default thing that the button is going to do, since we're specifying our own action for the button
e.preventDefault();
// We'll want to call display_scenario() with this option
display_scenario(option);
})
.appendTo('#options');
// Add the next option button
add_option_button(index + 1);
}
add_option_button(0);
}
// This function waits until the document is ready
$(document).ready(function() {
// Start the story
display_scenario({
name: null,
path: 'intro'
});
});
#import url(http://fonts.googleapis.com/css?family=Open+Sans:400,700);
* {
margin: 0px;
padding: 0px;
color: #32363F;
font: 18px 'Open Sans', sans-serif;
border: none;
outline: none;
box-sizing: border-box;
}
html {
display: table;
width: 100%;
height: 100%;
}
body {
display: table-cell;
background: #32363F;
vertical-align: middle;
}
#wrapper {
margin: 40px;
background: #D6C2A3;
width: calc(100% - 80px);
}
h1 {
display: block;
padding: 20px 20px 12px;
font: 700 36px 'Open Sans', sans-serif;
background: #E84949;
color: #FAFAFA;
text-transform: uppercase;
}
#prompt {
padding: 20px;
}
#prompt p {
padding-bottom: 8px;
}
#prompt p b {
font-weight: 700;
}
#options {
display: flex;
padding: 0px 20px 28px;
text-align: center;
}
#options button {
margin: 0px 8px;
padding: 8px 20px;
background: #C2AE8F;
width: 100%;
cursor: pointer;
}
#options button:hover,
#options button:active {
background: #E84949;
color: #FAFAFA;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
<h1>Food Adventure</h1>
<div id="prompt"></div>
<div id="options"></div>
</div>

Related

My JS code is not working and the content of my two-question form is not displaying inside the central div. Could someone please fix my JS code?

Could someone please correct my JS code and tell me what was done in order to do so? I was wondering what did I do wrongly that leads my quiz questions and its alternatives to be not displayable inside the central div.
Contextualising my code: it is a two-questions form and the results of it should be displayed at the top of the page in the afterwards of a click in the Evaluate button, however my focus for now is to understand how one can make the quiz visible in the HTML/CSS page.
Link to CodePen: My code snippet
const quizQuestions = {
questions = {
question: "What is the of the state of Pará?",
alternatives: {
0: "São Paulo",
1: "Guarulhos",
2: "Campinas",
3: "São Bernardo do Campo",
4: "São José dos Campos",
5: "Santo André",
6: "Ribeirão Preto",
7: "Belém",
answer: "7"
},
{
question: "What is the capital of the state of Amapá?",
alternatives: {
0: "Osasco",
1: "Sorocaba",
2: "Mauá",
3: "Macapá",
4 "São José do Rio Preto",
5: "Mogi das Cruzes",
6: "Santos",
answer: "3"
};
document.getElementByClassName('.quiz-container ').addEventListener('click', function() {
let container =
document.querySelector('.quiz-container');
container.innerHTML = '<div class="quiz-container"></div>';
for (const [key, value] of Object.entries(quizQuestion.alternatives)) {
container.innerHTML += `<input type="radio" name="choice" value="${key}"> ${value}`;
}
container.innerHTML += '<div><button type="submit" id="submit-button">Evaluate</button></div>';
document.getElementById('submit2').addEventListener('click', function(event) {
console.log('asdf');
event.preventDefault();
var selected = document.querySelector('input[type="radio"]:checked');
if (selected && selected.value == quizQuestion.answer) {
alert('It is super, super correct :D!');
} else {
alert('Unfortunately, it is incorrect :(!');
}
});
});
body {
background: rgb(209, 29, 83);
margin: 0;
}
h1 {
background: rgb(255, 184, 201);
height: 60px;
margin: 0;
padding-left: 20px;
padding-top: 20px;
font-size: 45px;
text-shadow: 3px 3px 9px;
color: rgb(43, 29, 14);
}
.quiz-container {
text-align: left;
font-size: 25px;
background: rgb(255, 209, 220);
width: 700px;
height: 4000px;
margin: auto;
margin-top: 100px;
box-shadow: 9px 9px 10px;
margin-bottom: 60px;
}
button {
margin-left: 900px;
padding-top: 0;
margin-bottom: 60px;
}
.questions {
color: #000000;
text-align: center;
font-size: 15px;
}
<head>
<h1>QUIZ centred in Brazil</h1>
</head>
<body>
<div class="quiz-container"></div>
<div>
<button type="submit" id="submit-button">Evaluate</button>
</div>
<script src="js/main.js"></script>
</body>
There's a lot of issues in your code.
The first issue is your quizQuestions are structured wrong. They should be an array of objects, each containing a question, an array of alternatives, and an answer - I have corrected it in the snippet.
The second issue is with how you get the element - unique elements need to have unique ids don't use classes like that - which is why document.getElementByClassName does not exist, because it would be document.getElementsByClassName since classes are not unique like ids are. You also have a ., which is correct for a css selector or for jquery, but is not used in this form of getting - I updated it to use an id, correcting your css to match.
I am not sure how you were trying to do some of what you were doing, but this should be a workable starting point to get you moving again - I didn't include the question checking portion, since this was enough to get the box filled as you asked for.
const quizQuestions = [{
question: "What is the of the state of Pará?",
alternatives: [
"São Paulo",
"Guarulhos",
"Campinas",
"São Bernardo do Campo",
"São José dos Campos",
"Santo André",
"Ribeirão Preto",
"Belém"
],
answer:7
},{
question: "What is the capital of the state of Amapá?",
alternatives: [
"Osasco",
"Sorocaba",
"Mauá",
"Macapá",
"São José do Rio Preto",
"Mogi das Cruzes",
"Santos"
],
answer:3
}];
window.onload = function (){
const container = document.getElementById('quiz-container');
quizQuestions.forEach((question, number) => {
let questionHTML = `<div class="question"><h3>${question.question}</h3>`;
question.alternatives.forEach((value, key) => {
questionHTML += `<input type="radio" name="${number}choice" value="${key}">${value}<br />`;
});
questionHTML += "</div>";
container.innerHTML += questionHTML;
});
};
body {
background: rgb(209, 29, 83);
margin: 0;
}
h1 {
background: rgb(255, 184, 201);
height: 60px;
margin: 0;
padding-left: 20px;
padding-top: 20px;
font-size: 45px;
text-shadow: 3px 3px 9px;
color: rgb(43, 29, 14);
}
#quiz-container {
text-align: left;
font-size: 25px;
background: rgb(255, 209, 220);
width: 700px;
height: 4000px;
margin: auto;
margin-top: 100px;
box-shadow: 9px 9px 10px;
margin-bottom: 60px;
}
button {
margin-left: 900px;
padding-top: 0;
margin-bottom: 60px;
}
.question {
color: #000000;
text-align: center;
font-size: 15px;
}
<head>
<h1>QUIZ centred in Brazil</h1>
</head>
<body>
<div id="quiz-container"></div>
<div>
<button type="submit" id="submit-button">Evaluate</button>
</div>
<script src="js/main.js"></script>
</body>

Chaining button clicks with jQuery

I'm trying to build a simple website that let's you click 6 different buttons. Each click of the button is supposed to trigger the display of specific content (as an img file). Clicking each of the six buttons should lead to different content. I have managed to achieve this part via Javascript getElementById.
However, to add a bit more complexity, I want to implement sequential decision making. Meaning that clicking Button "1" and THEN clicking Button "2" (or 3-6 for that matter) should each lead to the display of other specific content. Likewise clicking Button "1", then "2" and then "1" again should also display specific content. My sequential decision making is supposed to be limited to only two buttons interacting until the end of the decision is reached. So essentially, something like 1 -> 2 -> 3 can not happen, but 3 -> 6 -> 3 can happen. I hope it's not too complicated what I'm trying to do.
Anyway, here's some code I wrote trying to achieve this, but I'm fairly sure that my toggle function is not the correct way to go about it as I'm essentially simply placing pictures above each other and there is no sequency to any of the decisions made. I think to achieve this, I would need to chain the clicks, but I'm completely lost as to how to achieve that. Any help is greatly appreciated.
a:link {
color: white;
text-decoration: none;
}
a:visited {
color: white;
text-decoration: none;
}
a:hover {
color: white;
text-decoration: none;
}
a:active {
color: white;
text-decoration: none;
}
a.pos:link {
color: black;
text-decoration: none;
}
a.pos:visited {
color: black;
text-decoration: none;
}
a.pos:hover {
color: white;
text-decoration: none;
}
a.pos:active {
color: black;
text-decoration: none;
}
a.button:link, a.button:visited {
margin: auto;
position: absolute;
top: 0px;
left: 0px;
background-color: yellowgreen;
width: 345px;
line-height: 20px;
height: 185px;
border: 2px solid;
border-color: white;
text-align: center;
border-radius: 100px;
font-family: open sans;
font-size: 9px;
color: black;
font-weight: 650;
color: white;
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
}
a.button:hover, a.button:active {
background-color: yellowgreen;
}
body {margin:0;}
ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
position: fixed;
top: 0;
width: 100%;
}
li {
float: left;
}
li a {
display: block;
color: white;
text-align: center;
padding: 20px 30px;
font-family: open sans;
text-decoration: none;
}
li a:hover:not(.active) {
background-color: #111;
}
.active {
background-color: #4CAF50;
}
h1 {
color: whitesmoke;
font-family: open sans;
font-size: 300%;
}
.table {
margin: auto;
position: relative;
width: 450px;
top: -1350px;
border: 6px solid #333333;
border-radius: 250px;
background: #737373;
padding-top: 150px;
padding-right: 50px;
padding-left: 50px;
padding-bottom: 150px;
}
#quattro {
margin: auto;
position: absolute;
bottom: -25px;
right: 250px;
background-color: gold;
width: 50px;
line-height: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
border-radius: 50px;
font-family: open sans;
font-size: 20px;
font-weight: 650;
}
#uno {
margin: auto;
position: absolute;
top: -25px;
right: 250px;
background-color: gold;
width: 50px;
line-height: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
border-radius: 50px;
font-family: open sans;
font-size: 20px;
font-weight: 650;
}
#duo {
margin: auto;
position: absolute;
top: 25px;
right: 10px;
background-color: gold;
width: 50px;
line-height: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
border-radius: 50px;
font-family: open sans;
font-size: 20px;
font-weight: 650;
}
#tres {
margin: auto;
position: absolute;
bottom: 25px;
right: 10px;
background-color: gold;
width: 50px;
line-height: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
border-radius: 50px;
font-family: open sans;
font-size: 20px;
font-weight: 650;
}
#cinqo {
margin: auto;
position: absolute;
bottom: 25px;
left: 10px;
background-color: gold;
width: 50px;
line-height: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
border-radius: 50px;
font-family: open sans;
font-size: 20px;
font-weight: 650;
}
#seis {
margin: auto;
position: absolute;
top: 25px;
left: 10px;
background-color: gold;
width: 50px;
line-height: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
border-radius: 50px;
font-family: open sans;
font-size: 20px;
font-weight: 650;
}
.imgrange1 {
text-align: center;
color: white;
position: absolute;
top: 400px;
left: -400px;
}
.imgrange2 {
text-align: center;
color: white;
position: absolute;
top: 400px;
left: 320px;
}
.centered {
font-family: open sans;
font-size: 150%;
position: absolute;
top: -3%;
left: 50%;
transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="css/style.css">
<style>
.myimgdivtoggle1 {
display: none;
}
.myimgdivtoggle2 {
display: none;
}
.myimgdivtoggle3 {
display: none;
}
.myimgdivtoggle4 {
display: none;
}
.myimgdivtoggle5 {
display: none;
}
</style>
<script>
$(document).ready(function(){
$('.togglebtn1').click(function(){
$('.myimgdivtoggle1').toggle();
});
});
$(document).ready(function(){
$('.togglebtn2').click(function(){
$('.myimgdivtoggle2').toggle();
});
});
$(document).ready(function(){
$('.togglebtn3').click(function(){
$('.myimgdivtoggle3').toggle();
});
});
$(document).ready(function(){
$('.togglebtn4').click(function(){
$('.myimgdivtoggle4').toggle();
});
});
$(document).ready(function(){
$('.togglebtn5').click(function(){
$('.myimgdivtoggle5').toggle();
});
});
$(document).ready(function(){
$('.togglebtn6').click(function(){
$('.myimgdivtoggle6').toggle();
});
});
</script>
</head>
<body>
<ul>
<li><a class="active" href="index.html">Main</a></li>
<li>News</li>
<li>Contact</li>
<li>About</li>
</ul>
<div style="padding:20px;margin-top:30px;background-color:cadetblue;height:1500px;">
<h1><center>TEST</center></h1>
</div>
<div class="table">
<button type="button" class="togglebtn1" id="uno">1</button>
<div class="myimgdivtoggle1">
<img src="1.JPG" class="imgrange1"/>
</div>
<button type="button" class="togglebtn2" id="duo">2</button>
<div class="myimgdivtoggle2">
<img src="2.JPG" class="imgrange1"/>
</div>
<button type="button" class="togglebtn3" id="tres">3</button>
<div class="myimgdivtoggle3">
<img src="3.JPG" class="imgrange1"/>
</div>
<button type="button" class="togglebtn4" id="quattro">4</button>
<div class="myimgdivtoggle4">
<img src="4.JPG" class="imgrange1"/>
</div>
<button type="button" class="togglebtn5" id="cinqo">5</button>
<div class="myimgdivtoggle5">
<img src="5.JPG" class="imgrange1"/>
</div>
<button type="button" class="togglebtn6" id="seis">6</button>
<div class="myimgdivtoggle6">
<img src="6.JPG" class="imgrange1"/>
</div>
</body>
</html>
Though I can not provide you with a firm solution, I can however offer a small example which illustrates how to incorporate an array which tracks the buttons that have been clicked, as well as a way to get certain content from combinations of buttons.
Run the example and try the combinations 363, 254, 521 and 165 to get some results showing up. I've tried my best to show what the produced output is.
I'd suggest that you take a look at it and ask any questions if you have them. I'll check in to see if you do.
$(document).ready(function() {
/**
* Select the buttons.
* The $display and $clickedButtons are just to output
* the values that are stored.
*/
const $buttons = $('.button');
const $display = $('#display');
const $clickedButtons = $('#clicked-buttons');
const $removeButton = $('#remove-button');
/**
* Array which tracks your clicked buttons.
* If a button is clicked, the value of that button should be added to this array.
* The combination of the values will then later represent the key.
*/
const values = [];
/**
* This is where any know combinations are stored.
* The values in the values array will later be transformed into a single string to
* see if it matches any key in the combinations object below.
* If it does, it will give you a value, otherwise undefined.
*/
const combinations = {
"363": "https://www.fillmurray.com/200/200",
"254": "https://www.fillmurray.com/220/220",
"521": "https://www.fillmurray.com/240/240",
"165": "https://www.fillmurray.com/300/300"
};
/**
* Combines the values to form a single key and check if that key matches a combination.
* If there is a match the content should be anything other than undefined.
*/
function tryCombination() {
// This will output the current values from the array.
$clickedButtons.text(values);
// Transform the array into a single string.
// This will be the key to select content.
// ["1", "2", "3"] becomes "123".
const key = values.join('');
// Check if key has a match in the combinations object.
const url = combinations[key];
if (url !== undefined) {
// It does, show the content.
$display.attr('src', url);
$display.removeClass('hidden');
} else {
// It doesn't, empty the content.
$display.removeAttr('src');
$display.addClass('hidden');
}
}
/**
* Listen for the click event on all the buttons.
* When clicked, get the value of that clicked button and add that to the values array.
* It then calls the tryCombination function to evaluate if the values in the values
* array make a valid combination.
*/
$buttons.on('click', function() {
// This is the currently clicked button.
const $button = $(this);
// Get the value of the button.
const value = $button.val();
// If there already are 3 previously clicked buttons,
// then empty the array, so we can start a new combination.
if (values.length === 3) {
values.length = 0;
}
// Now add the newly clicked value.
values.push(value);
// Render and try the combination.
tryCombination();
});
/**
* Remove the last item in the values array.
* Then retry to create a valid combination.
*/
$removeButton.on('click', function() {
// Remove the last item from the values array
values.pop();
// Render and try the new combination.
tryCombination();
})
});
.container {
display: grid;
grid-template-rows: auto auto;
grid-template-columns: 200px 1fr;
grid-gap: 1em;
border: 1px solid #d0d0d0;
background-color: #f7f7f7;
padding: 1em;
border-radius: 5px;
}
.buttons {
grid-area: 1 / 1 / 2 / 3;
}
#display {
grid-area: 2 / 1 / 3 / 2;
width: 200px;
height: 200px;
background-color: #d0d0d0;
border-radius: 5px;
}
#clicked-buttons {
grid-area: 2 / 2 / 3 / 3;
display: block;
background-color: #d0d0d0;
border-radius: 5px;
padding: 1em;
margin: 0;
}
#remove-button {
grid-area: 1 / 2 / 2 / 3;
}
.hidden {
opacity: 0;
visibility: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="buttons">
<button class="button" id="1" value="1" >1</button>
<button class="button" id="2" value="2" >2</button>
<button class="button" id="3" value="3" >3</button>
<button class="button" id="4" value="4" >4</button>
<button class="button" id="5" value="5" >5</button>
<button class="button" id="6" value="6" >6</button>
</div>
<img id="display" class="hidden">
<button id="remove-button">Remove last input</button>
<code id="clicked-buttons"></code>
</div>
Edit
In the spirit of showing is better than telling; your last comment was about having a loose combination of numbers. This adds another layer of complexity.
Objects can only have keys that are strings (or Symbols) to get and set values. But in your case you'll want an array of numbers which represent the keys in any order, so plain objects are not suitable anymore.
The solution for this is the Map object. This object can have any type of key and value. So we can make a link between a combination of numbers and the images they represent (hence the name "map").
The example below uses this method. I've written a function that checks if an array of numbers is a match with any combination in the map. And if it does it return an array of images, referring to your previous comment.
Check it out. I believe this one to be more complex, so once more feel free to ask questions.
/**
* Create a Map instance.
*/
const combinations = new Map();
/**
* Values and keys are added with the set() method.
* This could still be improved with a loop setting each
* combination / images pair.
*/
combinations.set([3, 3, 6], ['https://www.fillmurray.com/200/200', 'https://www.fillmurray.com/200/200']);
combinations.set([2, 4, 5], ['https://www.fillmurray.com/220/220', 'https://www.fillmurray.com/220/220']);
combinations.set([1, 2, 5], ['https://www.fillmurray.com/240/240']);
combinations.set([1, 5, 6], ['https://www.fillmurray.com/300/300', 'https://www.fillmurray.com/300/300', 'https://www.fillmurray.com/300/300']);
const tryCombination = (key, combinations) => {
/**
* Loop over every combination.
* [combination, images] exposes the key-value pair,
* it's just a syntax to write fewer lines
*/
for (const [combination, images] of combinations) {
/**
* Create an array for the matches. If a number of the
* combination is in the given key, then that number
* will be pushed to the matches list. In the end,
* if everything matches, we should have just as many
* matches as numbers in the combination. That way
* we know if a key is correct.
*/
const matches = [];
/**
* We'll do some manipulation on the combination array,
* so to keep it intact we make a copy and manipulate that instead.
*/
const combinationCopy = Array.from(combination);
/**
* Count backwards through the combination array.
* Backwards counting is necessary when you remove items
* from the array while looping. I'd suggest you look
* into that subject.
*/
for (let i = combinationCopy.length - 1; i >= 0; i--) {
/**
* Get the current number we're looping over.
*/
const number = combinationCopy[i];
/**
* If that number is in the key array..
*/
if (key.includes(number)) {
/**
* ..then push that number to the matches array..
*/
matches.push(number);
/**
* ..and remove it from the copied combination array.
* We do this to prevent duplicate hits for cases
* where you have multiple occurrences of the same number,
* like [3, 3, 6]. When the first 3 hits, it will be removed.
* Then we have [3, 6] and we know we only need one more
* 3 and a 6.
*/
combinationCopy.splice(i, 1);
}
}
/**
* Now if every number has been matched correctly, then
* the amount of matches should be the same as the length
* of the combination. If that is the case, return the
* images. Otherwise, do nothing.
*/
if (matches.length === combination.length) {
return images;
}
}
/**
* If there are no matches, just return false, notifying the
* user that the combination is incorrect.
*/
return false;
};
console.log(tryCombination([5, 4, 2], combinations)); // Hit!
console.log(tryCombination([5, 1, 6], combinations)); // Hit!
console.log(tryCombination([2], combinations)); // Fail!
console.log(tryCombination([5, 4, 4], combinations)); // Fail!
console.log(tryCombination([3, 6, 3], combinations)); // Hit!

BEGINNER: Removing items from Javascript Array

I am coding a random quote generator. I almost have it fully coded how I want. I am a beginner in HTML and I've never used Javascript before this weekend. I took from multiple tutorials to code this exactly how I want it and am very proud. I have one last thing I am trying to do. When a item from the array is called, I want it to be removed, stored in another array and when the original array reaches 0, I want it to reset. I know its possible but I am not sure what to add to this script to make it work. Thanks so much for any help.
const quotes = [{
game: 'CARD TYPE 1',
quote: "This is the card description for Card Type 1",
rule: "Card Type 1 Rules"
},
{
game: 'CARD TYPE 2',
quote: "This is the card description for Card Type 2",
rule: "Card Type 2 Rules"
},
{
game: 'CARD TYPE 3',
quote: "This is the card description for Card Type 3",
rule: "Card Type 3 Rules"
}
];
const maincontainer = document.querySelector("#quoteBtn");
const questionStyle = document.querySelector("#quote");
const gameTitleStyle = document.querySelector("#gameTitle");
const ruleStyle = document.querySelector("#ruleTxt");
quoteBtn.addEventListener("click", displayQuote);
function displayQuote() {
let number = Math.floor(Math.random() * quotes.length);
gameTitle.innerHTML = quotes[number].game;
quote.innerHTML = quotes[number].quote;
ruleTxt.innerHTML = quotes[number].rule;
}
<style type="text/css">
body {
font-family: "Poppins", sans-serif;
background-color: #3F6BFF;
}
.maincontainer {
position: relative;
width: 500px;
height: 300px;
animation: flip 1s;
text-align: center;
margin: 0 auto;
border-radius: 25px;
}
.thecard {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: all 0.5s ease;
border-radius: 25px;
}
.thecard:active {
transform: rotateY(360deg);
}
.thefront {
position: absolute;
width: 100%;
height: 100%;
padding-right: 30px;
padding-left: 30px;
backface-visibility: hidden;
background-color: #fff;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
}
.theback {
position: absolute;
width: 100%;
height: 100%;
padding-right: 30px;
padding-left: 30px;
backface-visibility: hidden;
transform: rotateY(180deg);
background: #000;
border-radius: 25px;
}
.gameTitleStyle {
font-weight: 800;
font-size: 32px;
text-transform: uppercase;
}
.ruleStyle {
position: relative;
top: -20px;
font-style: italic;
}
.questionStyle {
position: relative;
top: 20px;
font-size: 18px;
}
</style>
<body>
<div class="maincontainer" id="quoteBtn">
<div class="thecard">
<div class="thefront">
<h1 class="gameTitleStyle" id="gameTitle">Business Name</h1>
<p class="ruleStyle" id="ruleTxt">Rules</p>
<p class="questionStyle" id="quote">Card Description</p>
</div>
<div class="theback"></div>
</div>
</div>
</body>
Removing an element from an array can be done with the Array.prototype.splice() method. For example, this removes element 2 from an array called "items", and returns the removed element in a new array:
let removedItems = items.splice(2);
Add items to an array using Array.prototype.push():
otherArray.push(...removedItems);
The ...removedItems converts the removedItems array to a list of items. The ... is called the spread operator.
These should be enough to accomplish what you want.

How can I insert a break between (multiple choice) answers in javascript?

I am making a quiz using javascript as a fun thing for my website. I followed a tutorial using https://www.sitepoint.com/simple-javascript-quiz/ , and after a bit of trial and error got it working with one question. But, as it is a multiple choice quiz, there are different choices to click on. The choices are all on one line. How can I change the code so that they are on separate lines? To help with any misconceptions, here are the choices and the code:
. a : 28 . b : 34 . c : 33 . d : More Information needed
<!DOCTYPE>
<html>
<style>
#sometext {
background-color: black;
border-radius: 10px;
border-left: 2px solid black;
border-right: 2px solid black;
border-top: 2px solid black;
border-bottom: 2px solid black;
color: white;
}
/* Add padding to containers */
.container {
padding: 16px;
background-color: #9999;
}
.navbar {
overflow: hidden;
background-color: #333;
font-family: Arial, Helvetica, sans-serif;
}
.navbar a {
float: left;
font-size: 16px;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.navbar a:hover{
background-color: red;
}
body {
font-family: Verdana, sans-serif;
margin: 0;
text-align: center;
background-color: rgb(150, 175, 200);
}
#p {
position: relative;
font-family: sans-serif;
text-transform: uppercase;
font-size: 2em;
letter-spacing: 4px;
overflow: hidden;
background: linear-gradient(90deg, #000, #fff, #000);
background-repeat: no-repeat;
background-size: 80%;
animation: animate 3s linear infinite;
-webkit-background-clip: text;
-webkit-text-fill-color: rgba(255, 255, 255, 0);
}
#Header {
background-color: rgb(150, 175, 200);
color: Black;
font-family: Courier;
font-size: 50px;
background-position: center;
text-shadow: 0 1px 0 #ccc,
0 2px 0 #c9c9c9,
0 3px 0 #bbb,
0 4px 0 #b9b9b9,
0 5px 0 #aaa,
0 6px 1px rgba(0,0,0,.1),
0 0 5px rgba(0,0,0,.1),
0 1px 3px rgba(0,0,0,.3),
0 3px 5px rgba(0,0,0,.2),
0 5px 10px rgba(0,0,0,.25),
0 10px 10px rgba(0,0,0,.2),
0 20px 20px rgba(0,0,0,.15);
}
#keyframes animate {
0% {
background-position: -500%;
}
100% {
background-position: 500%;
}
}
</style>
<body>
<nav class="navbar">
<a href = "file:///C:/Users/xenia/De
sktop/InfoSpace/Home.html">Home</a>
<a href = "file:///C:/Users/xe
nia/Desktop/InfoSpace/Profile.html">My Profile</a>
<a href = "file:///C:/Users/xenia/Desktop
/InfoSpace/Articles.html">Articles</a>
<a href = "file:///C:/Users/xenia
/Desktop/InfoSpace/Reviews.html">Reviews</a>
<a href = "file:///C:/Users/xenia/Desktop
/InfoSpace/Tutorials.html">Tutorials</a>
<a href = "file:///C:/Users/xe
nia/Desktop/InfoSpace/Help.html">Help</a>
</nav>
<h1 id="Header"><strong>INFOSPACE</strong></h1>
<p id="sometext">
<br />
This site is dedicated to provide information for budding scientists.
We aim to give you
a enjoyable and informative experience. If you experience a bug in
the
site please email Samuel Crawford at samuelhbc#icloud.com. Our blogs are reviews of products.
In each one there is a link to the product. If the link is no longer relevent please email samuelhbc#icloud.com.
Thank you for your attention and enjoy!!!
<br />
<br />
</p>
<br />
<br />
<h1><strong>IQ Test</strong></h1>
<div id = "quiz">
</div>
<button id = "submit"><h1>Submit Quiz</h1></button>
<div id = "results">
</div>
<br />
<br />
<p id="p">A website for young scientists.</p>
</body>
<script>
const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const submitButton = document.getElementById('submit');
const myQuestions = [
{
question: "What is the next number in this sequence:
1,1,2,3,5,8,13,21...",
answers: {
a: "28",
b: "34",
c: "33",
d: "More Information needed"
},
correctAnswer: "b"
},
];
function buildQuiz() {
const output = [];
myQuestions.forEach(
(currentQuestion, questionNumber) => {
const answers = [];
for(letter in currentQuestion.answers){
answers.push(
`<label>
<input type="radio" name="question${questionNumber}"
value="${letter}">
${letter} :
${currentQuestion.answers[letter]}
</label>`
);
}
output.push(
`<div class="question"> ${currentQuestion.question} </div>
<div class="answers"> ${answers.join('')} </div>`
);
}
);
quizContainer.innerHTML = output.join('');
}
function showResults() {
const answerContainers = quizContainer.querySelectorAll('.answers');
let numCorrect = 0;
myQuestions.forEach( (currentQuestion, questionNumber) => {
const answerContainer = answerContainers[questionNumber];
const selector = 'input[name=question'+questionNumber+']:checked';
const userAnswer = (answerContainer.querySelector(selector) || {}).value;
if(userAnswer===currentQuestion.correctAnswer){
numCorrect++;
answerContainers[questionNumber].style.color = 'lightgreen';
}
else{
answerContainers[questionNumber].style.color = 'red';
}
});
resultsContainer.innerHTML = numCorrect + ' out of ' +
myQuestions.length;
}
buildQuiz();
submitButton.addEventListener('click', showResults);
</script>
</html>
One relatively easy way to do this would be to use Flexbox. In this case, you would add the following styles to your document:
.answers {
display: flex;
flex-direction: column;
}
display: flex makes the .answers divs flex elements, and flex-direction: column displays the div's content from top to bottom instead of from left to right. Once you have that, you can apply other flex properties to arrange the answers even more precisely to your liking. If you want to read more about how to use Flexbox, this article is a good place to get started.
One note about Flexbox though: It doesn't work especially well on older browsers (e.g. IE 11) if that is a concern.

Vue.js custom select component with v-model

I want to create a custom select component in Vue.js. Since I need specific options styling, I need to create 'select' made of div's etc that looks and acts like a real html select.
Currently I have something like this:
Vue.component('child', {
template: `<div class="component-container" #click="showOptions = !showOptions">
<div class="component__select">
<span class="component__select--name">Select Fruit</span>
<span class="c-arrow-down" v-if="!showOptions"></span>
<span class="c-arrow-up" v-if="showOptions"></span>
</div>
<ul class="component__select-options" v-if="showOptions" >
<li class="select--option" v-for="option in options">
<label> <input type="checkbox" :value="option"/> {{option.name}}</label>
</li>
</ul>
</div>`,
methods: {
selectOption(option) {
this.$emit('option', option)
}
},
data: () => ({
showOptions: false,
}),
props: ['options']
});
var vm = new Vue({
el: '#app',
data: () => ({
options: [
{id: 0, name: 'Apple'},
{id: 1, name: 'Banana'},
{id: 2, name: 'Orange'},
{id: 2, name: 'Strawberry'},
],
selectedFruit: ''
}),
})
.component__select {
height: 38px;
background-color: #F5F7FA;
border: 1px solid #dddddd;
line-height: 38px;
display: grid;
max-width: 500px;
grid-template-columns: 10fr 1fr;
}
.component__select--name {
font-size: 0.8rem;
padding: 0 0 0 25px;
cursor: pointer;
}
.c-arrow-down {
justify-self: end;
}
.component__select-options {
max-height: 180px;
border: 1px solid #dddddd;
border-top: none;
overflow: auto;
position: absolute;
z-index: 1500;
max-width: 500px;
width: 500px;
margin: 0;
padding: 0;
}
.select--option {
height: 35px;
display: grid;
align-content: center;
padding: 0 0 0 25px;
background-color: #f5f5fa;
border-bottom: 1px solid #dddddd;
}
.select--option:last-child {
border-bottom: none;
}
.select--option:nth-child(2n) {
background-color: #ffffff;
}
.select--option input{
display: none;
}
.single-option {
height: 55px;
background-color: #2595ec;
font-size: 0.8rem;
border: 1px solid red;
}
.cust-sel {
width: 200px;
height: 38px;
background-color: #f5f5fa;
border: 1px solid #dddddd;
}
.cust-sel:focus {
outline-width: 0;
}
<html>
<head>
<title>An example</title>
</head>
<body>
<div id="app">
<span> This is parent component</span>
<p>I want to have data from select here: "{{selectedFruit}}"</p>
<child :options="options" v-model="selectedFruit"></child>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</body>
</html>
But my problem is now how to return data from child to parent component using v-model on child component.
(I know I could emit data from child component and do:
<custom-select :options="someOptions" #selected="setSelectedOption"/>
but I need it to be reusable and writing more and more methods to retrieve data from every select in parent component is not exactly how it should work I think.)
Also I need to have an entire object returned, not only ID. (that's why i've got :value="option")
Any ideas?
As Vue Guide said:
v-model is essentially syntax sugar for updating data on user input
events, plus special care for some edge cases.
The syntax sugar will be like:
the directive=v-model will bind value, then listen input event to make change like v-bind:value="val" v-on:input="val = $event.target.value"
So for your use case, you need to create one prop=value, then emit the selected option with event=input.
Like below demo (bind/emit the whole option object):
Vue.config.productionTip = false
Vue.component('child', {
template: `<div class="component-container" #click="showOptions = !showOptions">
<div class="component__select">
<span class="component__select--name">{{value ? value.name : 'Select Fruit'}}</span>
<span class="c-arrow-down" v-if="!showOptions"></span>
<span class="c-arrow-up" v-if="showOptions"></span>
</div>
<ul class="component__select-options" v-if="showOptions" >
<li class="select--option" v-for="option in options" #click="selectOption(option)">
<label> <input type="checkbox" :value="option"/> {{option.name}}</label>
</li>
</ul>
</div>`,
methods: {
selectOption(option) {
this.$emit('input', option)
}
},
data: () => ({
showOptions: false
}),
props: ['options', 'value']
});
var vm = new Vue({
el: '#app',
data: () => ({
options: [
{id: 0, name: 'Apple'},
{id: 1, name: 'Banana'},
{id: 2, name: 'Orange'},
{id: 2, name: 'Strawberry'},
],
selectedFruit: ''
}),
})
.component__select {
height: 38px;
background-color: #F5F7FA;
border: 1px solid #dddddd;
line-height: 38px;
display: grid;
max-width: 500px;
grid-template-columns: 10fr 1fr;
}
.component__select--name {
font-size: 0.8rem;
padding: 0 0 0 25px;
cursor: pointer;
}
.c-arrow-down {
justify-self: end;
}
.component__select-options {
max-height: 180px;
border: 1px solid #dddddd;
border-top: none;
overflow: auto;
position: absolute;
z-index: 1500;
max-width: 500px;
width: 500px;
margin: 0;
padding: 0;
}
.select--option {
height: 35px;
display: grid;
align-content: center;
padding: 0 0 0 25px;
background-color: #f5f5fa;
border-bottom: 1px solid #dddddd;
}
.select--option:last-child {
border-bottom: none;
}
.select--option:nth-child(2n) {
background-color: #ffffff;
}
.select--option input{
display: none;
}
.single-option {
height: 55px;
background-color: #2595ec;
font-size: 0.8rem;
border: 1px solid red;
}
.cust-sel {
width: 200px;
height: 38px;
background-color: #f5f5fa;
border: 1px solid #dddddd;
}
.cust-sel:focus {
outline-width: 0;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<span> This is parent component</span>
<p>I want to have data from select here: "{{selectedFruit}}"</p>
<child :options="options" v-model="selectedFruit"></child>
</div>
When using v-model on custom component all you need is to declare a prop named 'value' and when you need the component to chance it emit an 'input' event.
Something like this:
<template>
<form #submit.prevent="$emit('onSearch',val)" class="form-perfil">
<div class="form-group col-md-12">
<input v-model="val" #input="$emit('input',val)"
placeholder="filtrar resultados" class="form-control">
</div>
</form>
</template>
<script>
module.exports = {
name: "CaixaFiltro",
props: ["value"],
data: _ => ({ val: "" }),
created() {
this.val = this.value
}
}
</script>
Then you can use (after register the component) it like this:
<caixa-filtro v-model="textoBusca" #onSearch="listar"></caixa-filtro>
You can find more detailed info there:

Categories

Resources