I am very new to javaScript and I am currently trying to code a Lottery Game. The User is allowed to input 6 numbers between 1 and 49 and then Generate 6 random numbers and it will then tell you how many Numbers you got correct.
Everything seems to be working great so far but i can not figure out how to Code that you
Can not input the same number twice (This should result in an error code)
The Randomizer isnt allowed to draw the same number twice
My Code looks like this so far:
function validateBall(num) {
let ballValue = document.getElementById("ball" + num).value;
if (ballValue == "") {
alert("Ball " + num + " braucht eine Zahl");
return false;
}
if (isNaN(ballValue)) {
alert("Ball " + num + " ist keine Zahl");
return false;
}
let numberValue = parseInt(ballValue);
if (numberValue <= 0 || numberValue > 49) {
alert("Die Zahl des Balls muss zwischen 1-49 liegen");
return false;
}
return numberValue;
}
function containsDuplicates(ballValue) {
return array.length !== new Set(ballValue).size;
}
function output(str) {
let output = document.getElementById("output");
var tag = document.createElement("p");
var text = document.createTextNode(str);
tag.appendChild(text);
output.appendChild(tag);
}
function Jetzt_Spielen() {
let value1 = validateBall("1");
if (value1 == false)
return;
let value2 = validateBall("2");
if (value2 == false)
return;
let value3 = validateBall("3");
if (value3 == false)
return;
let value4 = validateBall("4");
if (value4 == false)
return;
let value5 = validateBall("5");
if (value5 == false)
return;
let value6 = validateBall("6");
if (value6 == false)
return;
let values = [value1, value2, value3, value4, value5, value6];
let outputDiv = document.getElementById("output");
outputDiv.innerHTML = "";
let matched = 0;
for (let i = 0; i < 6; i++) {
let randomNumber = Math.round(1 + Math.random() * 48);
output("Gezogene Zahl: " + randomNumber);
for (let j = 0; j < 6; j++) {
let myBallValue = values[j];
if (randomNumber == myBallValue) {
matched++;
break;
}
}
}
output("Du hast " + matched + " richtige Zahl(en)")
}
<div class="gelbe_box">
<h1>Lotto 6aus49</h1>
</div> <br>
<div class="position_middle">
<input id="ball1" class="LottoZahlen" />
<input id="ball2" class="LottoZahlen" />
<input id="ball3" class="LottoZahlen" />
<input id="ball4" class="LottoZahlen" />
<input id="ball5" class="LottoZahlen" />
<input id="ball6" class="LottoZahlen" />
<button id="submitBtn" value="button" onclick=" Jetzt_Spielen();">Jetzt Spielen</button>
<div id="output">
</div>
I dont really know how to continue with this. I either did something wrong already that I cant do it with this code or I just can not figure the code(s) out..
I'd really appreciate some help!!
Thank you in advance :)
Good UX and Restrictions
Plan the layout (HTML and essential CSS) first. To control how interaction with the user is done relies heavily on HTML and CSS, JavaScript is used to facilitate this interaction, gather user data, and process user's data and/or new data. In order to answer your question, I'm compelled to show you an approach to meet your objective and provide a solution that's foolproof for your particular problem.
HTML
If you require interaction from a user use a <form> and keep all of your relevant layout inside of it. Present only what the user needs to use, ideally a single form control like a button. Hide the rest of the HTML and restrict the user to go through phases. Instruct the user with simple messages and visual prompts. Don't use prompt() (it's aesthetically unappealing and popups feel "rude" IMO):
Figure I - The Layout
<form id='lottery'><!-- Wrap <form> around everything -->
<fieldset id='box'>
<!-- Always have simple clear directions -->
<legend>Click the button to begin</legend>
<!-- Offer the user only one or two choices at a time -->
<!-- ATM there are two empty <select> and a <button> that automatically
has focus (see Figure II). There's a <legend> prompting user to click
the <button>. There's also a hidden <button> and <output> ready for
the next phase.
-->
<select id='choices' multiple></select>
<!-- This button has focus as soon as the page is loaded because it's
assigned "tab-index='0'" and there's a line of JavaScript
(see Figure II)
-->
<button id='begin' tab-index='0'>Begin</button>
<button id='done' tab-index="0" type='button'>Done</button>
<select id='picked' multiple></select>
</fieldset>
<output id='note' class='hide'>
<small><sup>✳️</sup>To deselect a number, click the number in field on the right</small>
</output>
<!-- This hidden section is the final phase which displays the user's
numbers, the winning lottery numbers, and the numbers that matched.
-->
<fieldset id='results' class='hide'>
<label for='final'>Your Numbers: </label><output id='final' class='array'></output><br>
<label for='targets'>Winning Numbers: </label><output id='targets' class='array'></output><br>
<label for='hits'>Matching Numbers: </label><output id='hits' class='array'></output><br>
<button type='reset'>Replay</button>
</fieldset>
</form>
JavaScript
// This will hold the numbers the user picks
let numbers = [];
/*
This is an array of 49 empties "". It will be used as a counter and
then later repurposed to hold the winning numbers
*/
let A49 = [...Array(49)];
/*
Throughout this example the terse syntax of the HTMLFormsElement
interface will be used extensively. This references the <form>
*/
const lot = document.forms.lottery;
// 1st phase init(e) populates a <select> with 49 <option>s
lot.addEventListener('submit', init);
/*
2nd phase pick(e) allows the user to pick 6 numbers, no need to validate
user input there are 49 numbers and each number can only be picked once.
*/
lot.addEventListener('input', pick);
/*
Last phase draw(e) collects the users array of 6 numbers, then generates
a randomized array of 6 numbers, then displays both arrays with matches
highlighted.
*/
lot.elements.done.addEventListener('click', draw);
lot.onreset = function() {
window.location.reload();
};
lot.elements.begin.focus();
function init(e) {
e.preventDefault();
const IO = this.elements;
A49 = A49.map((_, index) => {
IO.choices.insertAdjacentHTML(
'beforeend',
`<option value="${index + 1}">${index + 1}</option>`
);
return index + 1;
});
//...
This answer is huge, apologies, I'll return later on to finish explaining the rest of this code. It's foolproof and meets if not exceeds all objectives of the OP, I hope this helps.
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<style>
html {
font: 300 5vmin/1.25 'Segoe UI';
}
fieldset {
max-width: 15rem;
}
#box {
display: flex;
justify-content: center;
align-items: center;
}
input,
button,
output,
select,
label {
display: inline-block;
margin: 4px;
font: inherit;
}
button {
padding-bottom: 0.25rem;
border: 0;
border-radius: 2px;
outline: 0;
cursor: pointer;
}
label {
width: 4rem;
margin-right: 0;
}
mark {
padding: 1px;
background-color: #0047AB;
color: gold;
}
small {
font-size: 0.5rem;
}
legend b {
font-family: Consolas;
}
select {
width: 3rem;
height: 9rem;
border: 0.5 inset lightgrey;
border-radius: 2px;
outline: 0;
font-family: Consolas;
}
#choices {
overflow-y: scroll;
scrollbar-width: thin;
}
#choices::-webkit-scrollbar {
width: 0.25rem;
height: 9rem;
}
#picked {
overflow-y: hidden;
}
.array {
width: 7.5rem;
font-family: Consolas;
}
.hide {
visibility: hidden;
}
#done {
display: none;
}
#note {
margin-top: -4px;
}
[type='reset'] {
float: right;
}
select:focus,
button:focus {
color: #0047AB;
box-shadow: 0 0 0 2pt cornflowerblue;
}
</style>
</head>
<body>
<form id="lottery">
<fieldset id="box">
<legend>
Click the button to begin
</legend>
<select id="choices" multiple></select>
<button id="begin" tab-index="0">Begin</button>
<button id="done" tab-index="0" type="button">Done</button>
<select id="picked" multiple></select>
</fieldset>
<output id="note" class="hide">
<small>
<sup>✳️</sup>To deselect a number, click the number in field on the
right
</small>
</output>
<fieldset id="results" class="hide">
<label for="final">Your Numbers: </label>
<output id="final" class="array"></output><br />
<label for="targets">Winning Numbers: </label>
<output id="targets" class="array"></output><br />
<label for="hits">Matching Numbers: </label>
<output id="hits" class="array"></output><br />
<button id='replay' tab-index='0' type="reset">Replay</button>
</fieldset>
</form>
<script>
let numbers = [];
let A49 = [...Array(49)];
const lot = document.forms.lottery;
lot.addEventListener('submit', init);
lot.addEventListener('input', pick);
lot.elements.done.addEventListener('click', draw);
lot.onreset = function() {
window.location.reload();
};
lot.elements.begin.focus();
function init(e) {
e.preventDefault();
const IO = this.elements;
A49 = A49.map((_, index) => {
IO.choices.insertAdjacentHTML(
'beforeend',
`<option value="${index + 1}">${index + 1}</option>`
);
return index + 1;
});
IO.box.firstElementChild.innerHTML = `Pick <b>6</b> numbers -- 1 to 49<sup><small>✳️</small></sup>`;
IO.note.classList.remove('hide');
IO.begin.remove();
IO.done.style.display = 'inline-block';
IO.done.disabled = true;
IO.choices.focus();
}
function pick(e) {
const IO = this.elements;
const sel = e.target;
if (sel.id === 'choices') {
const copy = sel.options[sel.selectedIndex].cloneNode(true);
IO.picked.append(copy);
numbers.push(+sel.value);
sel.options[sel.selectedIndex].remove();
}
if (sel.id === 'picked') {
const copy = sel.options[sel.selectedIndex].cloneNode(true);
IO.choices.append(copy);
let nodeList = [...IO.choices.options];
let ordered = nodeList.sort((a, b) => +a.value - +b.value);
IO.choices.replaceChildren(...nodeList, ...ordered);
numbers = numbers.filter((number) => number !== +sel.value);
sel.options[sel.selectedIndex].remove();
}
if (numbers.length === 6) {
IO.choices.disabled = true;
IO.done.disabled = false;
IO.done.focus();
} else {
IO.choices.disabled = false;
IO.done.disabled = true;
}
IO.box.firstElementChild.innerHTML = `Pick <b>${
6 - numbers.length
}</b> numbers -- 1 to 49<sup><small>✳️</small></sup>`;
}
function draw(e) {
const IO = this.closest('form').elements;
IO.box.disabled = true;
IO.note.classList.add('hide');
IO.results.classList.remove('hide');
let drawn = shuffle(A49);
drawn.length = 6;
let match = drawn.filter((number) => numbers.includes(number));
IO.final.innerHTML = mark(numbers, match);
IO.targets.innerHTML = mark(drawn, match);
let outcome = match.length > 0 ? mark(match) : 'Goose Egg 🥚';
IO.hits.innerHTML = outcome;
IO.replay.focus();
}
function shuffle(array) {
let qty = array.length,
temp,
i;
while (qty) {
i = Math.floor(Math.random() * qty--);
temp = array[qty];
array[qty] = array[i];
array[i] = temp;
}
return array;
}
function mark(arrayA, arrayB = arrayA) {
arrayA.sort((a, b) => a - b);
return arrayA.map((n) =>
arrayB.includes(n) ? `<mark>${n}</mark>` : n
);
}
</script>
</body>
</html>
Related
/* Nonfications, Thanks to MDN */
function notifyMe() {
// Let's check if the browser supports notifications
if (!("Notification" in window)) {
alert("This browser does not support desktop notification");
}
// Let's check whether notification permissions have already been granted
else if (Notification.permission === "granted") {
// If it's okay let's create a notification
var notification = new Notification("Take a break!");
}
// Otherwise, we need to ask the user for permission
else if (Notification.permission !== "denied") {
Notification.requestPermission().then(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
var notification = new Notification("Hi there!");
}
});
}
// At last, if the user has denied notifications, and you
// want to be respectful there is no need to bother them any more.
}
notifyMe()
//Read localStorage:
/*
if (localStorage.getItem('object') === undefined) {
localStorage.setItem('object', '')
} else {
//let objectData = localStorage.getItem('object');
let objectData = {
section: {
heading: {
task: 'label'
}
},
studyRoutine: {
onweekdays: {
mathBook: 'important'
},
onweekends: {
mathBook: 'important',
scienceBook: 'notimportant'
}
}
}
alert(objectData[1])
// loop sections
alert(objectData.length)
for (var i = 0; i < objectData.length; i++) {
// loop headings
for (var y = 0; y < objectData[i].length; y++) {
// loop tasks
for (var x = 0; x < objectData[i][y].length; x++) {
const myElementMade = document.createElement('input');
myElementMade.setAttribute('type', 'text')
}
}
}
}
*/
/* Add deleted elements and refer to it when created in same place / position */
window.deletedSections = [];
window.deletedHeadings = [];
window.deletedTasks = [];
const sidebar = document.getElementById('sidebarTasks');
/* Counts each element so they can have different id's to be selected */
window.counter = 0;
window.counterHeadings = 0;
window.counterLabel = 0;
window.counterLabelDelete = 0;
window.counterTasks = 0;
window.counterBr = 0;
/* To avoid any interferance there is a seperate delete function for tasks(because properties of tasks differ) */
const deleteTask = (taskid) => {
}
/* Delete sections and headings */
const deleteType = (labelAdd, labelDelete, inputType, spacing) => {
/* Remove elements given as id's */
document.getElementById(labelAdd).remove()
/* Insert div so div can be used to append later */
//document.getElementById(labelDelete).insertAdjacentHTML('afterend', `<div id="${inputType}"></div>`)
document.getElementById(labelDelete).remove()
document.getElementById(inputType).remove()
document.getElementById(spacing).remove()
/* Check if inputType is section or heading */
//if (inputType.slice(0, 7) === 'element') {
/* Push to section counter */
//window.deletedSections.push(inputType)
//} else if (inputType.slice(0, 7) === 'heading') {
/* Push to heading counter */
//window.deletedHeadings.push(inputType)
//}
}
/* New task */
const newTask = (id, labelid) => {
// Counter tasks for id's that work
window.counterTasks++
window.counterLabel++
const heading = document.getElementById(id);
const label = document.getElementById(labelid);
// Insert task input
label.insertAdjacentHTML('afterend', `<br><input placeholder="task" name="task" type="text" id="task${window.counterTasks}" style="position: relative; left: 4vw;"></input>`)
// Insert button to go to the task
document.getElementById(`task${window.counterTasks}`).insertAdjacentHTML('afterend', `<label for="task" style="position: relative; left: 4vw;" id="label${window.counterLabel}"><button onclick="checkTask()">></button></label>`)
}
const newHeading = (id, labelid) => {
const sectionElement = document.getElementById(id);
// Counter for headings and id's
window.counterHeadings++
window.counterLabel++
// test declared to fix some bugs but might be unnessary
const test = 'element' + window.counterHeadings;
// creat heading input
//document.getElementById(`${labelid}`)
/*
if (window.counterHeadings > 1) {
if (document.getElementById(`heading${window.counterHeadings - 1}`).nextElementSibling.nextElementSibling.id.slice(0, 4) !== 'task') {
document.getElementById(`heading${window.counterHeadings - 1}`).nextElementSibling.insertAdjacentHTML('afterend', `<br><input placeholder="heading" name="heading" type="text" id="heading${window.counterHeadings}" style="position: relative; left: 2vw;"></input>`)
// insert label button "+"
document.getElementById(`heading${window.counterHeadings}`).insertAdjacentHTML('afterend', `<label for="heading" style="position: relative; left: 2vw;" id="label${window.counterLabel}"><button onclick="newTask('heading${window.counterHeadings}', 'label${window.counterLabel}')">+</button></label>`);
} else {
alert(document.querySelectorAll(`#heading${window.counterHeadings - 1} > *`));
document.getElementById(`heading${window.counterHeadings - 1}`).nextElementSibling.insertAdjacentHTML('afterend', `<br><input placeholder="heading" name="heading" type="text" id="heading${window.counterHeadings}" style="position: relative; left: 2vw;"></input>`)
// insert label button "+"
document.getElementById(`heading${window.counterHeadings}`).insertAdjacentHTML('afterend', `<label for="heading" style="position: relative; left: 2vw;" id="label${window.counterLabel}"><button onclick="newTask('heading${window.counterHeadings}', 'label${window.counterLabel}')">+</button></label>`);
}
} else {
document.getElementById(`${labelid}`).insertAdjacentHTML('afterend', `<br><input placeholder="heading" name="heading" type="text" id="heading${window.counterHeadings}" style="position: relative; left: 2vw;"></input>`)
// insert label button "+"
document.getElementById(`heading${window.counterHeadings}`).insertAdjacentHTML('afterend', `<label for="heading" style="position: relative; left: 2vw;" id="label${window.counterLabel}"><button onclick="newTask('heading${window.counterHeadings}', 'label${window.counterLabel}')">+</button></label>`);
}
*/
if (window.counterHeadings > 1) {
window.counter = 0;
window.counterPrev = [labelid];
while (true) {
console.log(window.counterPrev[counter]);
window.counterPrev.push(document.getElementById(window.counterPrev[window.counterPrev.length]).nextElementSibling.id)
window.counter++
if (window.counter > 20) {
break;
}
}
} else {
document.getElementById(`${labelid}`).insertAdjacentHTML('afterend', `<br><input placeholder="heading" name="heading" type="text" id="heading${window.counterHeadings}" style="position: relative; left: 2vw;"></input>`)
// insert label button "+"
document.getElementById(`heading${window.counterHeadings}`).insertAdjacentHTML('afterend', `<label for="heading" style="position: relative; left: 2vw;" id="label${window.counterLabel}"><button onclick="newTask('heading${window.counterHeadings}', 'label${window.counterLabel}')">+</button></label>`);
}
}
const addSection = () => {
// counter for section, label and <br>
window.counter++
window.counterLabel++
window.counterBr++
const newSection = document.createElement('input');
// add attributes to section and appendChild() because section is not moved to the right so this is a better aprroach
newSection.setAttribute('placeholder', 'section');
newSection.setAttribute('name', 'section');
newSection.setAttribute('type', 'text');
newSection.id = 'element' + window.counter;
// test again
const test = 'element' + window.counter;
sidebar.appendChild(newSection)
const label = document.createElement('label');
// label with "+"
label.setAttribute('for', 'section');
label.innerHTML = `<button onclick="newHeading('element${window.counter}', 'label${window.counterLabel}')">+</button>`;
label.id = `label${window.counterLabel}`;
console.log(label.innerHTML);
sidebar.appendChild(label)
// delete label "X"
document.getElementById(`label${window.counterLabel}`).insertAdjacentHTML('afterend', `<label for="section" id="labelDelete${window.counterLabelDelete}"><button onclick="deleteType('label${window.counterLabel}', 'labelDelete${window.counterLabelDelete}', 'element${window.counter}', 'br${window.counterBr}')">X</button></label>`)
// br has id so can be deleted and not take up space.
const br = document.createElement('br');
br.id = `br${window.counterBr}`;
sidebar.appendChild(br);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="sidebarTasks">
<button onclick="addSection()">Add new section</button> <br>
<input id="" name="section" type="text" placeholder="section"> <label for="section"><button id="">+</button></label> <br>
<input id="" name="heading" type="text" placeholder="heading" style="position: relative; left: 2vw;"> <label for="heading" style="position: relative; left: 2vw;"><button id="" onclick="newTask(this.id)">+</button></label> <br>
<input id="" name="task" type="text" placeholder="task" style="position: relative; left: 4vw;" style="position: relative; left: 2vw;"> <label for="task" style="position: relative; left: 4vw;"><button id="">></button></label> <br>
</div>
<script src="script.js"></script>
</body>
</html>
(please don't take any code from here I worked hard)
Try making a new section, pressing the + twice and you see the error.
There is a lot of code but focus on:
if (window.counterHeadings > 1) {
window.counter = 0;
window.counterPrev = [labelid];
while (true) {
console.log(window.counterPrev[counter]);
window.counterPrev.push(document.getElementById(window.counterPrev[window.counterPrev.length]).nextElementSibling.id)
window.counter++
if (window.counter > 20) {
break;
}
}
I'm trying to make it so I can iterate through each element after my heading input but it keeps on giving errors that say it's null or .nextElementSibling is getting a wrong property, what I'm getting is Javascript can't find the element id I'm giving it but I don't know why, it should be correct based on my knowledge.
EDIT:
This was my code before
if (window.counterHeadings > 1) {
window.counter = 0;
window.counterPrev = `${labelid}`
while (true) {
console.log(window.counterPrev);
window.counterPrev = document.getElementById(window.counterPrev).nextElementSibling.id
window.counter++
if (window.counter > 20) {
break;
}
}
Please note I'm new at Javascript and I'm only at regex section in freecodecamp so please explain everything you say, thank you!
I am trying to make a simple game using JavaScript and HTML.
The game consists of having two buttons on the screen with random numbers and clicking the one that is smaller.
At the end, you will get your results.
What I am having trouble with is getting the random number generated in JavaScript to print on the button and getting the data back to JavaScript from the button.
var number = prompt('Choose Your Difficulty, Easy, Normal, Or Hard?');
var number = number.toUpperCase(); //Chooses difficulty
if (number === 'EASY')//easy difficulty
{
var difficulty = 20;
}else if (number === 'NORMAL')//normal difficulty
{
var difficulty = 100;
}else if(number === 'HARD')//hard difficulty
{
var difficulty = 1000;
}else
{
alert('Please Enter A Valid Answer')//if value is not valid
}
var number1 = Math.floor((Math.random()* difficulty) + 1);//random number 1
var number2 = Math.floor((Math.random()* difficulty) + 1);//random number 2
//----------------------Code i found but im not sure now to use it--------------
// 1. Create the button
var button = document.createElement("button");
button.innerHTML = "Do Something";
// 2. Append somewhere
var body = document.getElementsByTagName("body")[0];
body.appendChild(button);
// 3. Add event handler
button.addEventListener("click", function() {
alert("did something");
});
//-----------------------------------------------------------------------------
button {
margin-top: 20px;
line-height: 60px;
font-weight: bold;
padding: 0 40px;
background: salmon;
border: none;
}
button:hover {
background: lightsalmon;
}
<!DOCTYPE html>
<html>
<head>
<title>
Speed Game
</title>
<link href="css/styles.css" rel="stylesheet"
type="text/css">
<script src="../script/script.js"></script>
</head>
<body>
<button id= "button">
Do Something!
</button>
</body>
</html>
How can I solve this problem?
First of all, welcome to the world of programming!
Second, here's the game you wanted. I've done everything using functions, so understanding it should be easy.
Try to play a few games first!
The concept is pretty simple, really, so after playing a bit, look at the code and try to figure it out on your own!
var number;
var difficulty = 0;
var randomNumOne;
var randomNumTwo;
var buttonOne = document.getElementById("buttonOne");
var buttonTwo = document.getElementById("buttonTwo");
var tempButton;
function requestDifficulty(){
number = prompt('Choose Your Difficulty, Easy, Normal, Or Hard?');
number = number.toUpperCase();
setDifficulty();
}
function setDifficulty(){
if (number === 'EASY'){
difficulty = 20;
startGame();
}else if (number === 'NORMAL'){
difficulty = 100;
startGame();
}else if(number === 'HARD'){
difficulty = 1000;
startGame();
}else{
alert('Please Enter A Valid Answer');
requestDifficulty()
}
}
function startGame(){
randomNumOne = Math.floor((Math.random()* difficulty) + 1);
randomNumTwo = Math.floor((Math.random()* difficulty) + 1);
buttonOne.innerHTML = randomNumOne;
buttonTwo.innerHTML = randomNumTwo;
}
function getResults(pressedButton){
tempButton = pressedButton;
if(tempButton == "buttonOne"){
if(randomNumOne < randomNumTwo){
alert("Correct!")
}else{
alert("False!")
}
}else if(tempButton == "buttonTwo"){
if(randomNumTwo < randomNumOne){
alert("Correct!")
}else{
alert("False!")
}
}
}
requestDifficulty();
button {
margin-top: 20px;
line-height: 60px;
font-weight: bold;
padding: 0 40px;
background: salmon;
border: none;
}
button:hover {
background: lightsalmon;
}
<!DOCTYPE html>
<html>
<head>
<title>
Speed Game
</title>
</head>
<body>
<button id="buttonOne" onclick="getResults('buttonOne');">
random number 1
</button>
<button id="buttonTwo" onclick="getResults('buttonTwo')">
random number 2
</button>
</body>
</html>
I am trying to make an interface where you can select tickets and buy them, I want that when I click on a seat it displays like "You are currently buying the next tickets + (The tickets chosen by the user)".
This is my code so far:
var seatsUnclicked = document.getElementsByClassName("seat-unique");
var seatsClicked = document.getElementsByClassName("seatClicked");
var images = document.getElementsByTagName("IMG");
var seatsOutput = document.getElementsById("seatsOutput");
var ticketsData = 0
for (let i = 0; i < seatsUnclicked.length; i++) {
seatsUnclicked[i].onmouseover = function() {
this.src = "chairclicked.svg";
this.onmouseout = function() {
this.src = "chair.svg"
}
if ($(this).hasClass('seatClicked')) {
this.src = "chairclicked.svg";
this.onmouseout = function() {
this.src = "chairclicked.svg"
}
}
}
seatsUnclicked[i].onclick = function() {
this.classList.add("new")
if ($(this).hasClass('seatClicked')) {
this.classList.remove("seatClicked")
this.classList.remove("new")
this.src = "chair.svg";
this.onmouseout = function() {
this.src = "chair.svg"
}
ticketsData = ticketsData - /* "the id of this element in a string" */
}
if ($(this).hasClass('new')) {
this.src = "chairclicked.svg";
this.classList.add("seatClicked")
this.classList.remove("new")
this.onmouseout = function() {
this.src = "chairclicked.svg"
}
ticketsData = ticketsData + /* "the ID of this element in a string" */
}
seatsOutput.innerHTML = "THE TICKETS YOU HAVE CHOSEN ARE" + string(ticketsData)
}
}
<div class="seats-row-A">
<img id="A1" class="seat-unique " src="http://via.placeholder.com/100x100?text=A1">
<img id="A2" class="seat-unique " src="http://via.placeholder.com/100x100?text=A2">
<img id="A3" class="seat-unique " src="http://via.placeholder.com/100x100?text=A3">
<img id="A4" class="seat-unique " src="http://via.placeholder.com/100x100?text=A4">
<img id="A5" class="seat-unique" src="http://via.placeholder.com/100x100?text=A5">
<img id="A6" class="seat-unique " src="http://via.placeholder.com/100x100?text=A6">
<img id="A7" class="seat-unique " src="http://via.placeholder.com/100x100?text=A7">
</div>
<h2 id="seatsOutput">Chosen Tickets:</h2>
jQuery
The only jQuery statement in OP code is: $(this).hasClass('seatClicked').
The plain JavaScript equivalent is: this.classList.contains('seatClicked').
Question
I couldn't follow the OP code because there was only a class, an id, and img tags that match the JavaScript, but it's not that clear because of the *.svg files (not provided.) Also, there's a curly bracket } missing (I think it belongs to the for loop, but I'm not wasting time on debugging typos.)
The Demo was built in mind with what the question and comments had mentioned:
"...I want that when I click on a seat it displays like "You are currently buying..."
Highlight icon when hovered over.
Reveal icon's id when hovered on.
All hover behavior is done with CSS: :hover, ::before, ::after, content: attr(id), content: '\a0\1f4ba'. Using JavaScript for behavior CSS can do will result in more CPU cycles. CSS will use GPU of your graphics card instead of the CPU.
Testing
The seats are dynamically generated with id="A* by entering a number in the input and clicking the View button. For each additional click of the button a new batch of seats are appended and have ids that correspond to it's group:
input: 55 and first click A0-A55,
input: 12 and second click B0-B12,
input: 222 and third click C0-C222
...
Last group is J
References
The Demo is basically a <form>. HTMLFormControlsCollection API is used to set/get form controls and values.
Reference the tag
const ui = document.forms.tickets;
This is a collection of all form controls in form#tickets
const t = ui.elements;
Now all form controls are now accessible by prefixing a form control's #id or [name] with the HTMLFormControlsCollection Object.
<textarea name='textA'></textarea>
Without HFCC API
var ta = document.querySelector('[name=textA]');
With HFCC API
var ta = t.textA;
The links are collected by Links Collection.
document.links
DocumentFragment is used to insert a huge amount of dynamic HTML in one shot efficiently and quickly.
document.createDocumentFragment();
Various array methods were used:
Array.from()
map()
fill()
indexOf()
Demo
const ui = document.forms.tickets;
const t = ui.elements;
const seats = document.getElementById('seats');
t.btn.addEventListener('click', seatsAvailable);
seats.addEventListener('click', function(e) {
let picked = [];
pickSeat(e, picked);
}, false);
function pickSeat(e, picked) {
const display = t.display;
if (e.target.tagName === "A") {
e.target.classList.toggle('picked');
picked = Array.from(document.querySelectorAll('.picked'));
}
picked = picked.map(function(seat, index, picked) {
return seat.id;
});
display.value = "";
display.value = picked;
}
function seatsAvailable(e) {
const qty = this.previousElementSibling;
const last = document.links[document.links.length - 1].id;
console.log(last);
const limit = parseInt(qty.value, 10) + 1;
const spots = new Array(limit);
spots.fill(0, 0, limit);
return generateSeats(spots, last);
}
function generateSeats(spots, last) {
if (last.charAt(0) === "J") {
t.display.textContent += "Last row available";
return false;
}
const rowID = ['x', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
let row = rowID.indexOf(last.charAt(0)) + 1;
const frag = document.createDocumentFragment();
const avSeats = spots.map(function(A, idx) {
const seat = document.createElement('a');
seat.id = rowID[row] + idx;
seat.href = "#/";
frag.appendChild(seat);
return seat;
});
seats.appendChild(frag);
if (document.links[0].id === 'x') {
const x = document.getElementById('x');
x.parentElement.removeChild(x);
}
if (document.links.length > 114) {
const ext = (Math.round(document.links.length / 114)*600)+600;
seats.style.maxHeight = ext+'px';
}
return avSeats;
}
html,
body {
width: 100%;
height: 10%;
font: 400 16px/1.3 Consolas;
}
#seats {
display: flex;
flex-flow: column wrap;
max-height: 600px;
width: auto;
border: 3px ridge grey;
}
.box {
display: table
}
input,
button,
label {
font: inherit
}
#qty {
text-align: right
}
#display {
display: table-cell;
}
.tag {
overflow-x: scroll;
overflow-y: hidden;
display: block;
width: 400px;
line-height: 1.3
}
a,
a:link,
a:visited {
display: inline-block;
margin: 0;
text-align: center;
text-decoration: none;
transition: all 500ms ease;
}
a:hover,
a:active {
background: rgba(0, 0, 0, 0);
color: #2468ac;
box-shadow: 0 0 0 3px #2468ac;
}
a::before {
content: attr(id);
color: transparent;
}
a:hover::before {
color: #2468ac;
}
a.picked::before {
color: #000;
}
a::after {
content: '\a0\1f4ba';
font-size: 1.5rem;
}
#x {
pointer-events: none
}
.as-console-wrapper {
width: 30%;
margin-left: 70%
}
<form id='tickets'>
<fieldset class='box'>
<legend>Available Seats</legend>
<fieldset class='box'>
<input id='qty' type='number' min='0' max='50' value='1'> <button id='btn' type='button'>View</button>
<label class='tag'>Current ticket purchases to seats:
<output id='display'></output>
</label>
</fieldset>
<section id='seats'>
<a id='x' href='#/'></a>
</section>
</fieldset>
</form>
Okay so this is a bit hard to explain this, but I am trying to make where whenever a number is "spawned" or generated, it fades in instead of just popping up.
Here is the Fiddle that I am trying to do that with. I am using a input tag for the number and a for statement to generate the rest--
for (I = 0; I < $("#input:text").val(); I++) {
N.innerHTML += 1 + I + " "
}
I hope I explained that well enough so people understand!
Append span elements instead of text so that you can easily select elements using selector.
Use setTimeout to make it happen serially using index.
Try this:
var D = document,
In = D.getElementById("input"),
CC = D.getElementById("submit"),
N = D.getElementById("N"),
I;
$(In).keyup(function(Key) {
if (Key.keyCode == 13) {
for (var i = 0; i < $("#input:text").val().length; i++) {
var span = '<span style=\'display:none\'>' + (i + 1) + ' ' + $("#input:text").val()[i] + ' </span>'; //set display of `span` element as `none`
N.innerHTML += span;
}
}
$('#N span').each(function(i) {
setTimeout(function() {
$(this).hide().fadeIn(500);
}.bind(this), (i * 500)); // `.bind()` will pass the outer `this` context in`setTimeout` when handler is invoked
})
});
$(CC).click(function() {
N.innerHTML = "";
});
body {
cursor: default;
outline-width: 0px;
}
#main {
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<body>
<div id="main">
<input type="text" id="input" maxlength="3" placeholder="Press submit to clear all" />
<input type="submit" id="submit" />
</div>
<h1 id="N"></h1>
</body>
Fiddle here
The jQuery fadeIn method would make this trivial. But if you want to do this with no libraries you can modify the opacity of the result div in a recursive loop. I modified your fiddle here and included it below. The key points are setting the result div to opacity:0 at start, then recursively calling the "fadeIn" function after your original code has ran. you can tweak the timeout delay and opacity increment to get the desired speed and smoothness of the fade effect.
HTML:
<body>
<div id="main">
<input type="text" id="input" maxlength="3" placeholder="Press submit to clear all" />
<input type="submit" id="clear" />
</div>
<h1 id="N"></h1>
</body>
CSS:
body {
cursor: default;
outline-width: 0px;
}
#main {
text-align: center;
}
#N {
opacity: 0;
}
JavaScript:
var D = document,
In = D.getElementById("input"),
CC = D.getElementById("clear"),
N = D.getElementById("N"),
I,
O = 0;
var fadeIn = function() {
O += 0.05
D.getElementById("N").style.opacity = O;
if (O < 1) {
setTimeout(fadeIn, 100)
}
}
$(In).keyup(function(Key) {
if (Key.keyCode == 13) {
for (I = 0; I < $("#input:text").val(); I++) {
N.innerHTML += 1 + I + " "
}
setTimeout(fadeIn, 100)
}
});
$(CC).click(function() {
N.innerHTML = "";
});
How does citicards.com implement the login ID text box with special mask?
When you type "johndoe" and focus out the textbox becomes "jo***oe"
Is there a HTML5 mask with pattern?
Here is a sample implementation of the desired behaviour using pure javascript. This is just for a sample. You may need to do length check etc before actually using substr
document.querySelector("input#accountName").addEventListener("blur", function() {
var value = this.value;
document.querySelector("#maskedAccountName").textContent=this.value.substr(0,2)+this.value.substr(2,value.length-2).replace(/./g,"*")+this.value.substr(this.value.length-2, this.value.length);
this.style.display = "none";
document.querySelector("#maskedAccountName").style.display = "block";
}, false);
document.querySelector("#maskedAccountName").addEventListener("click", function() {
this.style.display = "none";
document.querySelector("input#accountName").style.display = "block";
document.querySelector("input#accountName").focus();
}, false);
div#maskedAccountName {
border: 1px solid rgba(231, 231, 231, 0.67);
padding: 2px;
display: none;
border-top-style: inset;
-webkit-appearance: textfield;
background-color: white;
width: 120px;
}
<input type="text" id="accountName">
<div id="maskedAccountName">
</div>
The reason why I'm not changing the existing input value is I may not be able to read the original value when accessed inside the form submit. So i've created a hidden div which is shown in place of the original input element. You can style the div to be same as the input element using CSS.
You have to use JS/jQuery. First count how mush letters from start and end you wish to take off, then replace everything else with * and append to fake input field.
You can see that in action here (replace opacity to 0 to completely hide input field, display: none will not work here, because you have to click on input itself):
$(document).ready(function() {
$("#hField").focusin(
function() {
$('#hFieldSp').text($(this).val());
});
$("#hField").focusout(function() {
var start = '';
var end = '';
var value = $(this).val();
var stars = '';
if (value.length < 3) {
return;
}
if (value.length > 6) {
start = value.substring(0, 2);
end = value.substring(value.length - 2);
stars = '*'.repeat(Math.max(1, value.length - 4));
} else {
start = value.substring(0, 1);
end = value.substring(value.length - 1);
stars = '*'.repeat(Math.max(1, value.length - 2));
}
$('#hFieldSp').text(start + stars + end);
});
$(document).on('input paste change', '#hField', function() {
$('#hFieldSp').text($(this).val());
});
});
String.prototype.repeat = function(num) {
return new Array(num + 1).join(this);
}
.wrapper {
float: left;
position: relative;
}
#hField,
#hFieldSp {
width: 100px;
height: 30px;
line-height: 30px;
border: 1px solid #ddd;
}
#hField {
opacity: .2;
position: absolute;
left: 0;
top: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div id="hFieldSp"></div>
<input type="text" id="hField" />
</div>
I would use a dummy input for the display. Then on blur, transfer the value to a hidden input and alter the text in the dummy. You might also want the reverse in place in case the user wants to alter the value: on focus, copy the value from the hidden input to the dummy. Here's a sample, no jQuery required, and if there are less than 5 characters in the input, it will make all *s instead.
var start = 0;
var end = 4;
var dummy_user = document.getElementById("user");
var actual_user = document.getElementById("hidden_user");
dummy_user.addEventListener("blur", function() {
actual_user.value = dummy_user.value;
if (dummy_user.value.length > 4) {
start = 2;
end = dummy_user.value.length - 2;
}
var val = "";
for (var i = 0; i < start; i++) {
val += dummy_user.value[i];
}
for (i = start; i < end; i++) {
val += "*";
}
for (i = end; i < dummy_user.value.length; i++) {
val += dummy_user.value[i];
}
dummy_user.value = val;
});
dummy_user.addEventListener("focus", function() {
this.value = actual_user.value;
});
<form action="">
<input type="text" name="user" id="user">
<input type="hidden" name="hidden_user" id="hidden_user" value="">
<input type="password" name="password">
<input type="submit" value="Sign in">
</form>