Style Binding makes app no show up anymore in Vue - javascript

What I'm trying to do is to make small 20px x 20px boxes of different colors in Vue. But, whenever I try to do :style='{ background-color: color.text }' (color is an object in the data with property text), it just breaks the app and it shows up with nothing.
Sceenshot without :style='{ background-color: color.text }'
Screenshot of inspector with :style='{ background-color: color.text }'
(No divs with id=app!)
Code:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Learning</title>
</head>
<body>
<style>
[v-cloak] {
display: none;
}
.color-box {
height: 20px;
width: 20px;
}
</style>
<div v-cloak id='app'>
<div id='product'>
<h1>{{ product }}</h1>
<div class='product-image'>
<img :src='image'>
</div>
<p v-if='inventory >= 50'>In stock</p>
<p v-else-if='10 <= inventory && inventory < 50'>Almost in stock</p>
<p v-else-if='inventory < 10'>Almost out of stock</p>
<p v-else-if='inventory == 0'>Out of stock</p>
<h3>Comes in the colors:</h3>
<div v-for='color in colors'
:key='color.id'
#mouseover='changeColor(color.image)' class='color-box'
:style='{ background-color: color.text }'>
</div>
<button #click='addToCart'>Add to cart</button>
<button #click='removeFromCart'>Remove item from cart</button>
<p># of items in cart: {{ cart }}</p>
</div>
</div>
<script src='https://cdn.jsdelivr.net/npm/vue'></script>
<script src='main.js'></script>
</body>
</html>
main.js
let app = new Vue({
el: '#app',
data: {
product: 'Socks',
image: '',
inventory: 9,
colors: idify([
{
text: "green",
image: 'socks.jpg'
},
{
text: "blue",
image: 'blue-socks.jpg'
}
]),
cart: 0,
},
methods: {
addToCart() { // ES6 shorthand for "addToCart: function() {"
this.cart += 1
},
removeFromCart() {
if (!this.cart) {
return;
}
this.cart -= 1
},
changeColor(image) {
this.image = image
},
}
})
app.image = app.colors[0].image
function idify(array) {
let idcount = 0
let array2 = []
for (let value of array) {
let obj = { id: idcount, ...value }
array2.push(obj);
idcount++;
}
return array2
}
function toTitleCase(str) {
return str.replace(
/\w\S*/g,
function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
}
);
}

background-color is not a valid property name in the object literal syntax because of the -.
You can fix it in these ways:
:style="{ backgroundColor: color.text }" (Vue-specific)
:style="{ 'background-color': color.text }"

Related

How to change style of element in click if its in a for loop in Javascript + Vue?

If I have an element like this that is in a for loop:
<p class="description" id="description" #click="onClickDescription">{{ review.text }}</p>
meaning that there is more than one of these elements, how can I change the style of the element that was clicked.
I have this function:
onClickDescription(e) {
console.log(e)
let d = document.getElementById('description');
d.style.webkitLineClamp = 99;
}
But this will change the style of all my <p> elements instead of just the one I clicked. How can I get around this?
You can use index or id if you have it in review object:
new Vue({
el: '#demo',
data() {
return {
reviews: [{text: 'aaa'}, {text: 'bb'}, {text: 'ccc'}],
selected: null
}
},
methods: {
onClickDescription(i) {
this.selected = i
}
}
})
.description {
color: green;
}
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-for="(review, i) in reviews" :key="i">
<p class="description" :class="i === selected && 'active'" #click="onClickDescription(i)">{{ review.text }}</p>
</div>
</div>

How to hide tooltip boxes in Vue

My goal is to get tooltip box popping up on each incorrect or empty input field when pressing 'Save' button.
I managed to display tooltip boxes by pressing 'Save' button, but when I input correct text (numbers), the tooltip box doesn't hide, but shows 'false' tooltip. How to hide tooltips completely on correct input?
full code: https://jsfiddle.net/a8bnp6m4/1/
var productForm = Vue.createApp ({})
productForm.component('custom-form', {
props: {
modelValue: {
type: String,
default: ''
},
},
components: ['status-bar', 'tooltips'],
template: `
<button v-on:click="submitProduct">Save</button>
<h1>Product Add</h1>
<div class="lines">
<label>SKU<input type="text" id="sku" v-model="this.product.sku" placeholder="ID"></label>
<tooltips v-if="this.tooltipText.show && showTooltip!=false" :tooltip="this.showTooltip(this.product.sku)" />
<label>Name<input type="text" id="name" v-model="this.product.name" placeholder="Please, provide name"></label>
<tooltips v-if="this.tooltipText.show && showTooltip!=false" :tooltip="this.showTooltip(this.product.name)" />
<label>Price<input type="text" id="price" v-model="this.product.price" placeholder="Please, provide price"></label>
<tooltips v-if="this.tooltipText.show && showTooltip!=false" :tooltip="this.showTooltip(this.product.price)" />
</div>
` ,
data: function() {
return {
product: {
sku: null,
name: null,
price: null,
},
options: ['DVD', 'Book', 'Furniture'],
selected: 'DVD',
tooltipText: {
onSubmit: 'Please, submit required data',
onType: 'Please, provide the data of indicated type',
show: false
}
}
},
computed:{
model:{
get(){ return this.modelValue },
set(v){ this.$emit('update:modelValue',v)}
}
},
methods:{
updateValue: function () {
return this.$emit('sendData')
},
submitProduct: function(){
for(var i in this.product){
this.showTooltip(this.product[i])
if(this.product[i]==null){
this.tooltipText.show = true
//this.product[i]=null
}
}
},
showData: function(){
//console.log(this.product.sku)
return JSON.stringify(this.product)
},
showTooltip: function(v){
if(v == null){ return this.tooltipText.onSubmit }
else if(!Number.isInteger(parseInt(v))){ return this.tooltipText.onType }
else { return false }
},
created() {
this.showData()
}
}
})
productForm.component ('tooltips', {
template: `
<div class="tooltip" :tooltip="tooltip" :showTooltip="showTooltip">
<span class="tooltiptext">{{tooltip}}</span>
</div>
`
})
const vm = productForm.mount('#product_form')
Today in about 10 minutes with clear head I solved my problem by replacing 'v-if' content with this.tooltipText.show && showTooltip(this.product.sku)!=false in my custom tooltip tag. :)
I just forgot to add an argument this.product.sku to showTooltip function.
full code: https://jsfiddle.net/amwfcv2o/
<label>SKU<input type="text" id="sku" v-model="this.product.sku" placeholder="ID"></label>
<tooltips v-if="this.tooltipText.show && showTooltip(this.product.sku)!=false" :tooltip="this.showTooltip(this.product.sku)" />
showTooltip: function(v){
if(v == null) { return this.tooltipText.onSubmit }
else if(!Number.isInteger(parseInt(v))) { return this.tooltipText.onType }
else { return false }
}
}
})
I suspect issue is with this.tooltipText.show && showTooltip!=false".
Can you try changing it to this.tooltipText.show && showTooltip"
Try without this in template and pass field in v-if showTooltip:
<label>SKU<input type="text" id="sku" v-model="product.sku" placeholder="ID"></label>
<tooltips v-if="tooltipText.show && showTooltip(product.sku)" :tooltip="showTooltip(product.sku)" />
...
Pls check following snippet:
var productForm = Vue.createApp ({})
productForm.component('custom-form', {
props: {
modelValue: {
type: String,
default: ''
},
},
components: ['status-bar', 'tooltips'],
template: `
<button v-on:click="submitProduct">Save</button>
<h1>Product Add</h1>
<div class="lines">
<label>SKU<input type="text" id="sku" v-model="product.sku" placeholder="ID"></label>
<tooltips v-if="tooltipText.show && showTooltip(product.sku)" :tooltip="showTooltip(product.sku)" />
<label>Name<input type="text" id="name" v-model="product.name" placeholder="Please, provide name"></label>
<tooltips v-if="tooltipText.show && showTooltip(product.name)" :tooltip="showTooltip(product.name)" />
<label>Price<input type="text" id="price" v-model="product.price" placeholder="Please, provide price"></label>
<tooltips v-if="tooltipText.show && showTooltip(product.price)" :tooltip="showTooltip(product.price)" />
</div>
` ,
data: function() {
return {
product: {
sku: null,
name: null,
price: null,
},
options: ['DVD', 'Book', 'Furniture'],
selected: 'DVD',
tooltipText: {
onSubmit: 'Please, submit required data',
onType: 'Please, provide the data of indicated type',
show: false
}
}
},
computed:{
model:{
get(){ return this.modelValue },
set(v){ this.$emit('update:modelValue',v)}
}
},
methods:{
showSelected: function(){
//return console.log(this.selected)
},
updateValue: function () {
return this.$emit('sendData')
},
submitProduct: function(){
for(var i in this.product){
this.showTooltip(this.product[i])
if(this.product[i]==null){
this.tooltipText.show = true
//this.product[i]=null
}
}
if (this.tooltipText.show == false){
//window.location.href = '../';
}
//console.log(this.product)
//return this.postData(this.product)
},
showData: function(){
//console.log(this.product.sku)
return JSON.stringify(this.product)
},
showTooltip: function(v){
if(v == null){ return this.tooltipText.onSubmit }
else if(!Number.isInteger(parseInt(v))){ return this.tooltipText.onType }
else { return false }
},
created() {
this.showData()
}
}
})
productForm.component ('tooltips', {
props: ['tooltip', 'showTooltip'],
//data: function(){
// return {
// tooltipText: this.tooltipText.onType
// }
//},
template: `
<div class="tooltip" :tooltip="tooltip" :showTooltip="showTooltip">
<span class="tooltiptext">{{tooltip}}</span>
</div>
`
})
const vm = productForm.mount('#product_form')
<!DOCTYPE html>
<html>
<head>
<title>scandiweb task</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
<link href="../styles.css" rel="stylesheet" type="text/css" media="all">
<!-- <script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script> -->
<script src="https://unpkg.com/vue#next"></script>
</head>
<body>
<style>
div input {
display:inline-block;
justify-content:space-between;
align-items:center;
border:3px solid black;
margin:10px;
padding:10px;
}
div label{
display:block;
}
.tooltip {
position: relative;
display: inline;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
position: absolute;
width: 400px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
margin-left:300px;
z-index: 1;
visibility: visible;
}
</style>
<div id="product_form" v-cloak>
<custom-form>
</custom-form>
</div>
</body>
</html>

Set up a v-on:click directive inside v-for

I have displayed a list of images with some information. I want those images to be clickable. And when clicked it should show a div with saying "HI!!". I have been trying to add a variable as show:true in Vue data and tried to build some logic that show becomes false when clicked. But I have not been able to achieve it.
Below is the sample code:
template>
<div>
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div ><img :src="launch.links.patch.small" alt="No Image" title={{launch.name}} /></div>
<div>ROCKET NAME: {{launch.name}} </div>
<div>DATE: {{ launch.date_utc}} </div>
<div>SUCCESS: {{ launch.success}} </div>
<div>COMPLETENESS: {{ launch.landing_success}} </div>
</div>
<!-- <v-model :start="openModel" #close="closeModel" /> -->
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'SpaceXTimeline',
components: {
},
data: () => ({
launches : [],
openModel : false,
show : true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + " is launched");
console.log("DETAILS: "+ launch.details);
console.log("ROCKET INFO: "+ launch.links.wikipedia);
console.log("CREW DETAILS: "+ launch.crew);
console.log("Launchpad Name: "+ launch.launchpad);
this.openModel = true;
},
closeModel () {
this.openModel = false;
}
},
async created() {
const {data} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
}
};
</script>
<style scoped>
.list {
border: 1px solid black;
}
</style>
Thanks, and appreciate a lot.
v-model is a binding and not an element, unless you've named a component that? Is it a misspelling of "modal"?
Either way, sounds like you want a v-if:
<v-model v-if="openModel" #close="closeModel" />
Example:
new Vue({
el: '#app',
components: {},
data: () => ({
launches: [],
openModel: false,
show: true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + ' is launched');
console.log('DETAILS: ' + launch.details);
console.log('ROCKET INFO: ' + launch.links.wikipedia);
console.log('CREW DETAILS: ' + launch.crew);
console.log('Launchpad Name: ' + launch.launchpad);
this.openModel = true;
},
closeModel() {
this.openModel = false;
},
},
async created() {
const {
data
} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
},
})
Vue.config.productionTip = false;
Vue.config.devtools = false;
.modal {
cursor: pointer;
display: flex;
justify-content: center;
position: fixed;
top: 0;
width: 100%;
height: 100vh;
padding: 20px 0;
background: rgba(255, 255, 255, 0.5);
}
img {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<div id="app">
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div>
<img :src="launch.links.patch.small" alt="No Image" :title="launch.name" />
</div>
<div>ROCKET NAME: {{ launch.name }}</div>
<div>DATE: {{ launch.date_utc }}</div>
<div>SUCCESS: {{ launch.success }}</div>
<div>COMPLETENESS: {{ launch.landing_success }}</div>
</div>
<div v-if="openModel" #click="closeModel" class="modal">
MODAL
</div>
</div>

How to pass v-model value between components

I have a parent form component and a child. How do I pass data from one to another using v-model? They are in different files. I'm using the components of the Quasar Framework.
Parent Component
<template>
<q-input
label="Nome *"
lazy-rules
:rules="[val => (val && val.length > 0) || 'Por favor, digite o seu nome']"
v-model="nome"
/>
</template>
<script>
export default {
name: "Nome",
data() {
return {
nome: "Max"
};
}
};
</script>
Child Component
<template>
<div class="q-pa-md" style="max-width: 500px">
<q-form #reset="onReset" class="q-gutter-md">
<Nome> </Nome>
<div>
<q-btn label="Reset" type="reset" color="red" flat class="q-ml-sm" />
</div>
</q-form>
</div>
</template>
<script>
import Nome from "components/Nome.vue";
export default {
components: { Nome },
onReset() {
this.name = null;
}
};
</script>
How do I onReset() work?
Automatically translated.
I think you have some confusion about your child component and parent component. On your code Nome is the child component and the form that using Nome is the parent component.
You can use ref to call the reset method on Nome from the parent form component.
Here is a Working example -
Vue.component("nome-input", {
data(){
return {
input: ""
}
},
template: `
<input #input="onInput" type="text" v-model="input">
`,
methods: {
reset(){
this.input = ""
},
onInput(){
this.$emit('onInput', this.input);
}
}
});
Vue.component("user-form", {
data(){
return {
name: '',
}
},
components: {
},
template: `
<div>
{{name}}
<nome-input ref="nome" #onInput="updateName"></nome-input>
<button #click.prevent="save">Save</button>
<button #click.prevent="reset">reset</button>
</div>
`,
methods: {
save(){
console.log(this.name);
},
reset(){
this.name = "";
this.$refs.nome.reset();
},
updateName(value){
this.name = value;
}
}
});
new Vue({
el: "#app",
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<user-form></user-form>
</div>
</body>
</html>
Here is a jsfiddle link for the above codes https://jsfiddle.net/azs06/u4x9jw62/34/

change global variable with click event

I am trying to change a global variable with a click event and I'm stuck. I've tried it in the way the code is written below, and I'm getting the correct result in the console, but it's not working globally. How else can I do it?
const levels = {
easy: 5,
medium: 3,
hard: 2
}
let currentLevel = levels.hard
document.querySelector('#easyBtn').addEventListener('click', function () {
currentLevel = levels.easy
console.log (currentLevel)
})
<button id="easyBtn" type="button">Easy</button>
Full Code:
window.addEventListener('load', init);
// Globals
const levels = {
easy: 5,
medium: 3,
hard: 2
}
let currentLevel = levels.hard
document.querySelector('#easyBtn').addEventListener('click', function () {
currentLevel = levels.easy
console.log (currentLevel)
})
document.querySelector('#mediumBtn').addEventListener('click', function() {
currentLevel = levels.medium
console.log (currentLevel)
})
document.querySelector('#hardBtn').addEventListener('click', function() {
currentLevel = levels.hard
console.log (currentLevel)
})
let time = currentLevel;
let score = 0;
let isPlaying;
// DOM Elemennts
const wordInput = document.querySelector('#word-input');
const currentWord = document.querySelector('#current-word');
const scoreDisplay = document.querySelector('#score');
const timeDisplay = document.querySelector('#time');
const message = document.querySelector('#message');
const seconds = document.querySelector('#seconds');
const words = [
'hat',
'river',
'fun',
'billion',
'park',
'superman',
'quacky',
'juggler',
'word',
'race',
'bullet',
'computer',
'Anne',
'Jacob',
'Drew',
'garden',
'bike',
'waffle',
'hero',
'statue',
'loom',
'backpack',
'picture',
'stand',
'window',
'marker',
'bank',
'chord',
'lettuce',
'color'
];
//Initialize game
function init() {
seconds.innerHTML = currentLevel;
//load word from array
showWord(words);
//start matching on word input
wordInput.addEventListener('input', startMatch)
//call countdown every second
setInterval(countdown, 1000);
//check game status
setInterval(checStatus, 50);
}
//start match
function startMatch() {
if(matchWords()) {
isPlaying = true;
time = currentLevel + 1;
showWord(words);
wordInput.value = '';
score++;
}
//score is -1 display 0
if(score === -1) {
scoreDisplay.innerHTML = 0;
} else {
scoreDisplay.innerHTML = score;
}
}
//match current word to wordInput
function matchWords() {
if(wordInput.value === currentWord.innerHTML) {
message.innerHTML = 'Correct!!!'
return true;
} else {
message.innerHTML = '';
return false;
}
}
function showWord(words) {
// Generate random array index
const randIndex = Math.floor(Math.random() * words.length);
// Output random word
currentWord.innerHTML = words[randIndex];
}
function countdown() {
//make sure time is not run out
if(time > 0) {
time--;
}else if(time === 0) {
isPaying = false;
}
timeDisplay.innerHTML = time;
}
function checStatus() {
if (!isPlaying === false && time === 0) {
message.innerHTML = 'Game Over!!!';
score = -1;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.body {
background-color: #a8a8a8;
}
.header {
background-color: #4646c7;
display: flex;
justify-content: center;
height: 70px;
align-items: center;
}
.btnSpacing {
display: flex;
justify-content: space-around;
align-content: center;
width: 100;
}
#easyBtn {
display: flex;
justify-content: center;
}
#mediumBtn {
display: flex;
justify-content: center;
}
#hardBtn {
display: flex;
justify-content: center;
}
#seconds {
color: rgba(248, 2, 2, 0.753);
font-weight: bold
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="styles.css">
<title>Word Race</title>
</head>
<!DOCTYPE html>
<html lang="en">
<body class="body">
<header class="header">
<h1>Word Race</h1>
</header>
<br>
<div class="container text-center col-md-6 mx-auto ">
<!-- Buttons -->
<div class="btnSpacing">
<div>
<button id="easyBtn" type="button" class="btn btn-success">Easy</button>
</div>
<div>
<button id="mediumBtn" type="button" class="btn btn-warning">Medium</button>
</div>
<div>
<button id="hardBtn" type="button" class="btn btn-danger">Hard</button>
</div>
</div>
<br>
<br>
<!-- Word & Input -->
<div class="row">
<div class="col-md-6 mx-auto">
<p class="lead">Type The Given Word Within
<span id="seconds">5</span> Seconds:</p>
<h2 class="display-2 mb-5" id="current-word">hello</h2>
<input type="text" class="form-control form-control-lg" placeholder="Start typing..." id="word-input" autofocus>
<h4 class="mt-3" id="message"></h4>
<!-- Time & Score Columns -->
<div class="row mt-5">
<div class="col-md-6">
<h3>Time Left:
<span id="time">0</span>
</h3>
</div>
<div class="col-md-6">
<h3>Score:
<span id="score">0</span>
</h3>
</div>
</div>
<!-- Instructions -->
<div class="row mt-5">
<div class="col-md-12">
<div class="card card-body bg-secondary text-white">
<h5>Instructions</h5>
<p>Type each word in the given amount of seconds to score. To play again, just type the current word. Your score
will reset.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="js/main.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
What I take it you're asking is "Why isn't stuff like the time given updating when I update the variable?"
Javascript won't "listen" for changes on its own. After, you update the variable, you need to tell everything relying on it to also update.
There's a million different way to go about this (and a million libraries that try to make JavaScript essentially listen on changes). At the simplest level: you can try switching the currentLevel setting to a function, and have that also re-init the game.
setCurrentLevel(level) {
currentLevel = levels.easy
init()
// any other stuff that needs to be updated/reset
}
// ...
document.querySelector('#easyBtn').addEventListener('click', function () {
setCurrentLevel(levels.easy)
})
window.addEventListener('load', init);
// Globals
const levels = {
easy: 5,
medium: 3,
hard: 2
}
let currentLevel = levels.hard
document.querySelector('#easyBtn').addEventListener('click', function () {
setCurrentLevel(levels.easy)
})
document.querySelector('#mediumBtn').addEventListener('click', function() {
setCurrentLevel(levels.medium)
})
document.querySelector('#hardBtn').addEventListener('click', function() {
setCurrentLevel(levels.hard)
})
let time = currentLevel;
let score = 0;
let isPlaying;
// DOM Elemennts
const wordInput = document.querySelector('#word-input');
const currentWord = document.querySelector('#current-word');
const scoreDisplay = document.querySelector('#score');
const timeDisplay = document.querySelector('#time');
const message = document.querySelector('#message');
const seconds = document.querySelector('#seconds');
const words = [
'hat',
'river',
'fun',
'billion',
'park',
'superman',
'quacky',
'juggler',
'word',
'race',
'bullet',
'computer',
'Anne',
'Jacob',
'Drew',
'garden',
'bike',
'waffle',
'hero',
'statue',
'loom',
'backpack',
'picture',
'stand',
'window',
'marker',
'bank',
'chord',
'lettuce',
'color'
];
//Initialize game
function init() {
seconds.innerHTML = currentLevel;
//load word from array
showWord(words);
//start matching on word input
wordInput.addEventListener('input', startMatch)
//call countdown every second
setInterval(countdown, 1000);
//check game status
setInterval(checStatus, 50);
}
//start match
function startMatch() {
if(matchWords()) {
isPlaying = true;
time = currentLevel + 1;
showWord(words);
wordInput.value = '';
score++;
}
//score is -1 display 0
if(score === -1) {
scoreDisplay.innerHTML = 0;
} else {
scoreDisplay.innerHTML = score;
}
}
//match current word to wordInput
function matchWords() {
if(wordInput.value === currentWord.innerHTML) {
message.innerHTML = 'Correct!!!'
return true;
} else {
message.innerHTML = '';
return false;
}
}
function showWord(words) {
// Generate random array index
const randIndex = Math.floor(Math.random() * words.length);
// Output random word
currentWord.innerHTML = words[randIndex];
}
function countdown() {
//make sure time is not run out
if(time > 0) {
time--;
}else if(time === 0) {
isPaying = false;
}
timeDisplay.innerHTML = time;
}
function checStatus() {
if (!isPlaying === false && time === 0) {
message.innerHTML = 'Game Over!!!';
score = -1;
}
}
function setCurrentLevel(level) {
currentLevel = level;
init();
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.body {
background-color: #a8a8a8;
}
.header {
background-color: #4646c7;
display: flex;
justify-content: center;
height: 70px;
align-items: center;
}
.btnSpacing {
display: flex;
justify-content: space-around;
align-content: center;
width: 100;
}
#easyBtn {
display: flex;
justify-content: center;
}
#mediumBtn {
display: flex;
justify-content: center;
}
#hardBtn {
display: flex;
justify-content: center;
}
#seconds {
color: rgba(248, 2, 2, 0.753);
font-weight: bold
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="styles.css">
<title>Word Race</title>
</head>
<!DOCTYPE html>
<html lang="en">
<body class="body">
<header class="header">
<h1>Word Race</h1>
</header>
<br>
<div class="container text-center col-md-6 mx-auto ">
<!-- Buttons -->
<div class="btnSpacing">
<div>
<button id="easyBtn" type="button" class="btn btn-success">Easy</button>
</div>
<div>
<button id="mediumBtn" type="button" class="btn btn-warning">Medium</button>
</div>
<div>
<button id="hardBtn" type="button" class="btn btn-danger">Hard</button>
</div>
</div>
<br>
<br>
<!-- Word & Input -->
<div class="row">
<div class="col-md-6 mx-auto">
<p class="lead">Type The Given Word Within
<span id="seconds">5</span> Seconds:</p>
<h2 class="display-2 mb-5" id="current-word">hello</h2>
<input type="text" class="form-control form-control-lg" placeholder="Start typing..." id="word-input" autofocus>
<h4 class="mt-3" id="message"></h4>
<!-- Time & Score Columns -->
<div class="row mt-5">
<div class="col-md-6">
<h3>Time Left:
<span id="time">0</span>
</h3>
</div>
<div class="col-md-6">
<h3>Score:
<span id="score">0</span>
</h3>
</div>
</div>
<!-- Instructions -->
<div class="row mt-5">
<div class="col-md-12">
<div class="card card-body bg-secondary text-white">
<h5>Instructions</h5>
<p>Type each word in the given amount of seconds to score. To play again, just type the current word. Your score
will reset.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="js/main.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
Edit: It looks like there may be some other function that may need to also be rewritten like when/how the actual countdown is set (or some general refactoring so they're called in init are there are fewer global variables) but this is the rough answer. You need to explicitly tell the game when settings have been updated and when to re-run.

Categories