How do I set timeout after button has been clicked in vue - javascript

I need a background colour to go back to its default colour after 3 seconds, I am using the setTimeout method but it is not working, how do I properly use it in this situation? or do I use a transition
<div id="exercise">
<div>
<p>Current Value: {{ value }}</p>
<button #click="value += 5(); red();" :style="{ 'background-color': color }">Add 5</button>
<button #click="value += 1">Add 1</button>
<p>{{ result }}</p>
</div>
<div>
<input type="text" v-model="timer">
<p>{{ value }}</p>
</div>
</div>
new Vue({
el: "#exercise",
data: {
value: 0,
timer: 1000,
color:'pink',
},
methods:{
red() {
this.color = "red";
setTimeout(function() {
this.red = 0;
}, 1000);
}
},
computed: {
result: function() {
return this.value >= 37 ? "Not there yet" : "done";
}
},
watch: {
result: function(value) {
var vm = this;
console.log(value);
setTimeout(function() {
vm.value = 0;
}, 5000);
}
}
});

Try to use an arrow function for your setTimeout, as the setTimeout points the this to the global object. Arrow functions use lexical scoping and knows to bind the this to the inner function:
new Vue({
el: "#exercise",
data: {
value: 0,
timer: 1000,
color:'pink',
},
methods:{
red() {
this.color = "red";
setTimeout(() => {
this.color = "";
}, 1000);
}
},
computed: {
result: function() {
return this.value >= 37 ? "Not there yet" : "done";
}
},
watch: {
result: function(value) {
var vm = this;
console.log(value);
setTimeout(function() {
vm.value = 0;
}, 5000);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="exercise">
<div>
<p>Current Value: {{ value }}</p>
<button #click="red();" :style="{ 'background-color': color }">Add 5</button>
<button #click="value += 1">Add 1</button>
<p>{{ this.result }}</p>
</div>
<div>
<input type="text" v-model="timer">
<p>{{ value }}</p>
</div>
</div>
(Also, inside of your setTimeout, you were trying to change this.red = 0, when it should be this.color = "" :D

Related

Vue.JS - Combine Variable

<script>
var app = new Vue ({
el: '#app',
data : {
sentence: ''
},
methods: {
Q: function () {
this.sentence = "Q"
},
W: function () {
this.sentence = "W"
},
E: function () {
this.sentence = "E"
},
R: function () {
this.sentence = "R"
},
T: function () {
this.sentence = "T"
},
Y: function () {
this.sentence = "Y"
}
}
})
</script>
<div id="app">
<p>Sentence : {{ sentence }}</p>
<button #click="Q">Q</button>
<button #click="W">W</button>
<button #click="E">E</button>
<button #click="R">R</button>
<button #click="T">T</button>
<button #click="Y">Y</button>
</div>
The program is working. But first of all the user click 'Q' and after that click 'W', the input seems 'W' , i want this input: "QW" , it should be combine.
For example the user click Q, W and E, the input should be "QWE". How can i combine all of them? Maybe its easy but i couldnt find anywhere. I am beginner on VueJS
Can you help me?
You can easily concat the string from your template #click event like so :
Method 1
<div id="app">
<p>Sentence : {{ sentence }}</p>
<button #click="sentence += 'Q'">Q</button>
<button #click="sentence += 'W'">W</button>
<button #click="sentence += 'E'">E</button>
<button #click="sentence += 'R'">R</button>
<button #click="sentence += 'T'">T</button>
<button #click="sentence += 'Y'">Y</button>
</div>
Method 2
<div id="app">
<p>Sentence : {{ sentence }}</p>
<button #click="addToSentence('Q')">Q</button>
<button #click="addToSentence('W')">W</button>
<button #click="addToSentence('E')">E</button>
<button #click="addToSentence('R')">R</button>
<button #click="addToSentence('T')">T</button>
<button #click="addToSentence('Y')">Y</button>
</div>
with a dedicated method
data() {
return {
sentence: ''
}
},
methods: {
addToSentence(letter) {
this.sentence += letter
}
}
Method 3
<div id="app">
<p>Sentence : {{ sentence }}</p>
<button v-for="letter in ['Q','W','E','R','T','Y']" #click="addToSentence(letter)">{{ letter }}</button>
</div>
with a dedicated method
data() {
return {
sentence: ''
}
},
methods: {
addToSentence(letter) {
this.sentence += letter
}
}
Method 4
More compact
<div id="app">
<p>Sentence : {{ sentence }}</p>
<button v-for="letter in ['Q','W','E','R','T','Y']" #click="sentence += letter">{{ letter }}</button>
</div>
data() {
return {
sentence: ''
}
},
What you looking for is called concatenation
add an + infront of =
Example:
this.sentence = "Q" to this.sentence += "Q"
Thats the same as if you would write: this.sentence = this.sentence + "Q" its just a shortcut
var app = new Vue ({
el: '#app',
data : {
sentence: ''
},
methods: {
Q: function () {
this.sentence += "Q"
},
W: function () {
this.sentence += "W"
},
E: function () {
this.sentence += "E"
},
R: function () {
this.sentence += "R"
},
T: function () {
this.sentence += "T"
},
Y: function () {
this.sentence += "Y"
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>Sentence : {{ sentence }}</p>
<button #click="Q">Q</button>
<button #click="W">W</button>
<button #click="E">E</button>
<button #click="R">R</button>
<button #click="T">T</button>
<button #click="Y">Y</button>
</div>

How to change background color on click in vue

I am trying to change the background colour of an element on click of it using vue but it doesn't change, this is what i have come up with so far, also the onclick method has two functions and I read that this is the best way to input to onclick events in vue.
<div id="exercise">
<div>
<p>Current Value: {{ value }}</p>
<button #click="value += 5(); red();" :style="{ 'background-color': color }">Add 5</button>
<button #click="value += 1">Add 1</button>
<p>{{ result }}</p>
</div>
<div>
<input type="text" v-model="timer">
<p>{{ value }}</p>
</div>
</div>
js
new Vue({
el: "#exercise",
data: {
value: 0,
timer: 1000,
},
methods:{
red() {
this.color = "red";
}
},
computed: {
result: function() {
return this.value >= 37 ? "Not there yet" : "done";
}
},
watch: {
result: function(value) {
var vm = this;
console.log(value);
setTimeout(function() {
vm.value = 0;
}, 5000);
}
}
});
In data you must insert
data: {
value: 0,
timer: 1000,
color: null
},
and try use correct syntax: https://v2.vuejs.org/v2/guide/class-and-style.html#Object-Syntax-1
<button #click="value += 5(); red();" :style="{backgroundColor: color }">Add 5</button>

Selected option in radio button is not working

I am working in a quiz app using Cordova and vue.js in which question and option will be fetched from API. In this, a timer is used which will indicate how much time is remaining. For this, I have set the timer in mounted(), in which there is a callback function which will be called every 1-second later by using setInterval. But the problem is when the timer is on, if I select one radio button, if the value is false then it just move towards the last radio button among the 4 buttons. If the value is true then it doesnot move. This problem doesnot occur when the timer is off, then it works fine. Please help me out
<template>
<v-ons-page>
<div class="test_body">
<v-ons-card class="test_card">
<div class="timer" v-if="!timeStop">
<div class="minutes" v-text="this.data.minutes"></div>
<div class="seconds" id="seconds" v-text="secondsShown"></div>
</div>
<div class="timer" v-else>
<div class="minutes" v-text="this.data.minutes"></div>
<div class="seconds" v-text="secondsShown"></div>
</div>
<div v-for="(ques,index) in questions">
<div v-show="index===ques_index">
<p class="test_text">{{ ques.question_text }} </p>
<ol align="left">
<li class="test_list" v-for="choice in ques.choices">
<input type="radio" v-bind:value="choice.is_right" v-bind:name="index"
v-model=" userResponses[index] "> {{ choice.choice_text }}
</li>
</ol>
<p class="test_number" align="right">{{index+1}} /{{questions.length}} </p>
<v-ons-button class="prev_next_button" modifier="cta" style="margin: 6px 0"
v-if="ques_index > 0" #click="prev">
Prev
</v-ons-button>
<v-ons-button class="prev_next_button" modifier="cta" style="margin: 6px 0" #click="next">
Next
</v-ons-button>
</div>
</div>
<div v-show="ques_index === questions.length">
<h2>
Quiz finished
</h2>
<p>
Total score: {{ score() }} / {{ questions.length }}
</p>
<v-ons-button class="prev_next_button" modifier="cta" style="margin: 6px 0" #click="congratz">
Congratulation
</v-ons-button>
</div>
</v-ons-card>
</div>
</v-ons-page>
</template>
<script>
import swal from 'sweetalert';
import congratz from './congratulation';
export default {
data() {
return {
minute: 0,
seconds: 0,
interval: null,
started: true,
questions: {},
ques_index: 0,
userResponses: [],
}
},
beforeMount() {
this.question();
},
mounted() {
this.loaded()
},
methods: {
congratz() {
swal({
text: "Congratulation on Your First Exam!",
});
this.pageStack.push(congratz)
},
question() {
this.$http({
method: 'post',
url: this.base_url + '/exam/api/',
auth: {
username: 'l360_mobile_app',
password: 'itsd321#'
},
data: {
"id": this.$store.state.user.id,
"duration": this.data.minutes
}
}).then((response) => {
//alert(response.data.questions[0].question_text);
//var questions = [];
this.questions = response.data.questions;
})
.catch((error) => {
// alert(error);
});
},
next: function () {
this.ques_index++;
},
prev: function () {
this.ques_index--;
},
score() {
var c = 0;
for (var i = 0; i < this.userResponses.length; i++)
if (this.userResponses[i])
c++;
return c;
},
loaded: function () {
this.interval = setInterval(this.intervalCallback, 1000)
},
intervalCallback: function () {
if (!this.started) return false
if (this.seconds == 0) {
if (this.data.minutes == 0) {
return null
}
this.seconds = 59
this.data.minutes--
} else {
this.seconds--
}
},
},
computed: {
secondsShown: function () {
if (this.seconds < 10) {
return "0" + parseInt(this.seconds, 10)
}
return this.seconds
},
timeStop: function () {
if (this.ques_index === this.questions.length) {
this.started = false;
return this.seconds;
}
}
},
props: ['pageStack']
}
</script>
<style>
</style>
To keep the values of input tags unique, add choice_id after the choice.is_right. Use choice.is_right + '_' + choice.choice_id instead of choice.is_right. When you get the values just remove the _ and id or check if 'true' is a sub-string of the value.
<ol align="left">
<li class="test_list" v-for="choice in ques.choices">
<input type="radio" v-bind:value="choice.is_right + '_' + choice.choice_id" v-bind:name="index" v-model="userResponses[index]">{{ choice.choice_text }}
</li>
</ol>

Vue js, detect when a value changed to highlight its text

I have this simple a script that generate random number every few moments, everytime rand is not equals to the one before i want to change its backgound-color. possible?
So the random number generates 1,1,3 when it gets to 3 i want to hightlight the background. thanks
https://jsfiddle.net/keseyxgm/1/
new Vue({
el: '#app',
data: {
rand: 0
},
mounted : function(){
var me = this;
setInterval(function(){
me.rand = Math.floor(Math.random() * 4) + 1 ;
me.$forceUpdate();
},1000)
}
})
<div id="app">
<p>{{rand}}</p>
</div>
Make a data property to store whether the updated value is different from the current value and bind the background-color to that:
new Vue({
el: '#app',
data() {
return {
rand: 0,
diff: false
}
},
mounted() {
setInterval(() => {
let rand = Math.floor(Math.random() * 4) + 1 ;
this.diff = rand !== this.rand;
this.rand = rand;
}, 1000);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div id="app">
<p :style="{ 'background-color': (diff) ? 'gold' : 'initial' }">{{rand}}</p>
</div>
A nice approach is to use a watcher with a class binding.
See this js fiddle: https://jsfiddle.net/omarjebari/wjf8qbt0/18/
<div id="app">
<div class="random-element" v-bind:class="{ active: isChanged }">{{ rand }}</div>
</div>
<script>
new Vue({
el: "#app",
data: {
rand: 0,
isChanged: false,
},
mounted : function(){
setInterval(() => {
this.rand = Math.floor(Math.random() * 4) + 1;
}, 1000);
},
watch: {
rand(newVal, oldVal) {
console.log(`${newVal} vs ${oldVal}`);
if (newVal !== oldVal) {
this.isChanged = true;
setTimeout(() => {
this.isChanged = false;
}, 300);
}
}
},
})
</script>
<style>
div.random-element {
height: 30px;
color: black;
padding: 5px;
}
div.active {
background-color: red;
}
</style>

Vue2: Avoid mutating a prop directly inside component

I'm gettig this "Avoid mutating a prop directly", when checking if the persons input should get an invalid class because its empty.
<script type="text/x-template" id="srx">
<input type="number" name="persons" id="persons" value="" v-model="persons" :class="{invalid: !persons}">
</script>
<div id="app">
{{stepText}}
<sr-el :persons="1"></sr-el>
<button v-if="currentStep > 1" type="button" v-on:click="previous()">prev</button>
<button v-if="currentStep < 6" type="button" :disabled="currentStepIsValid()" v-on:click="next()">
next</button>
</div>
Vue.component('sr-el', {
template: '#srx',
props: ['persons'],
})
var App = window.App = new Vue({
el: '#app',
data: {
persons: '1'
currentStep: 1,
},
methods: {
currentStepIsValid: function() {
if (this.currentStep == 1) {
this.stepText = "Step 1;
return !(this.persons > 0);
}
},
previous: function() {
this.currentStep = this.currentStep - 1;
// prev slide
},
next: function() {
this.currentStep = this.currentStep + 1;
// next slide
}
}
})
You're getting that warning because you are binding persons to the input in the template via v-model. Changing the input's value will thus change the value of persons, which means the prop is getting mutated directly in your sr-el component.
You should set a new property equal to persons and pass that to v-model instead:
Vue.component('sr-el', {
template: '#srx',
props: ['persons'],
data: function() {
return {
inputVal: this.persons,
}
}
})
<input v-model="inputVal" ... />

Categories