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>
Related
So I'm bringing in data from a CMS which is dynamically creating a title, a size and an input field which the user will be able to change.
When I increase the input value (1, 2, 3, 4 etc) the value changes in all inputs.
I need to take the number of individual inputs and do something with it.
I can kind of get this to work if I have my input type set to number but I want to keep it set to text so I can use custom increment and decrement buttons.
As I said the buttons and the counter works but values clone to every input. I'm sure it's something to do with the increaseQty and decreaseQty functions..
I'm very new to Vue so be gentle.
Thanks a million - Code below
<template>
<div>
<div id="step2items0" class="inventory">
<div class="inner-wrap">
<label>Choose Your {{ selected }} Items</label>
</div>
<div id="tabBtns" class="hr">
<div class="inner-wrap mobile-center">
<div v-for="(tab, index) in tabs" :key="index" #click="selectTab(tab)" class="tab" :class="selected_tab == tab ? 'selected' : ''" >
{{ tab }}
</div>
</div>
</div>
<div class="items-wrap">
<div class="item" v-for="(row, index) in items" :key="index">
<span class="lbl">{{ row.item_title }}</span>
<span class="input-wrap" style="display: flex; flex-direction: column">
<input type="text" name="item_m3" class="number" :value="row.item_m3"/>
<small>Item M3</small>
</span>
<span class="input-wrap">
<i id="decreaseQty" aria-hidden="true" class="fa fa-caret-left prev-btn" #click="decreaseQty"></i>
<input id="quantity" type="text" class="number" :value="quantity"/>
<i id="increaseQty" aria-hidden="true" class="fa fa-caret-right nxt-btn" #click="increaseQty"></i>
</span>
<div class="clear"></div>
</div>
</div>
</div>
</div>
</template>
<script>
module.exports = {
props: ["selected", "content", "value"],
data: function () {
return {
tabs: [],
selected_tab: "",
items: [],
quantity: 0,
};
},
computed: {
},
methods: {
//
increaseQty() {
this.quantity++;
console.log("AMOUNT -", this.quantity);
},
decreaseQty() {
if (this.quantity === 0) {
alert("Negative quantity not allowed");
} else {
this.quantity--;
console.log("AMOUNT -", this.quantity);
}
},
//
selectTab: function (value) {
console.log("TAB: ", value);
this.selected_tab = value;
const { content } = this;
let { items } = this;
content.forEach(function (row) {
if (row.room_name == value) {
items = row.item;
items.forEach(function (row) {
item_title = row.item_title;
item_m3 = row.item_m3;
console.log(" - ", item_title, " - ", item_m3);
});
}
});
this.items = items;
},
},
mounted: function () {
const { selected, content, tabs } = this;
let { selected_tab, items } = this;
console.log("SELECTED: ", selected);
if (selected === "Household") {
content.forEach(function (row) {
if (row.is_household == true) {
tabs.push(row.room_name);
if (selected_tab == "") {
selected_tab = row.room_name;
items = row.item;
items.forEach(function (row) {
item_title = row.item_title;
item_m3 = row.item_m3;
console.log(" - ", item_title, " - ", item_m3);
});
}
}
});
} else if (selected === "Business") {
content.forEach(function (row) {
if (row.is_business == true) {
tabs.push(row.room_name);
if (selected_tab == "") {
selected_tab = row.room_name;
items = row.item;
items.forEach(function (row) {
item_title = row.item_title;
item_m3 = row.item_m3;
console.log(row.room_name, " - ", item_title, " - ", item_m3);
});
}
}
});
}
this.selected_tab = selected_tab;
this.items = items;
},
};
</script>
<style scoped>
</style>
Input increment is affecting all inputs
You can get individual values inside the v-for by storing the values in an array.
data: {
items: [],
itemValues: [],
},
And use v-model to bind the input (you are using v-bind:value, not v-model). You can check this answer to learn the difference.
<div class="item" v-for="(row, index) in items" :key="index">
<input type="text" v-model="itemValues[index]">
</div>
Here's a fiddle:
https://jsfiddle.net/jariway/jxv0k4y3/62/
I build a pagination component that works fine. But I don't know how to limit the shown items in the v-for loop and show the next items on the next page.
this is the pagination component:
<template>
<div>
<ul class="pagination">
<li class="pagination-item">
<button
type="button"
#click="onClickFirstPage"
:disabled="isInFirstPage"
>
First
</button>
</li>
<li class="pagination-item">
<button
type="button"
#click="onClickPreviousPage"
:disabled="isInFirstPage"
>
Previous
</button>
</li>
<li v-for="page in pages" :key="page.name" class="pagination-item">
<button #click="onClickPage(page.name)" type="button" :disabled="page.isDisabled" :class="{ active: isPageActive(page.name )}">
{{ page.name }}
</button>
</li>
<!-- Range of pages -->
<li>
<button
type="button"
#click="onClickNextPage"
:disabled="isInLastPage"
>
Next
</button>
</li>
<li>
<button
type="button"
#click="onClickLastPage"
:disabled="isInLastPage"
>
Last
</button>
</li>
</ul>
</div>
<script>
export default {
props: {
maxVisibleButtons: {
type: Number,
required: false,
default: 3
},
totalPages: {
type: Number,
required: true
},
total: {
type: Number,
required: true
},
currentPage: {
type: Number,
required: true
}
},
computed: {
startPage() {
// When on the first page
if(this.currentPage === 1) {
return 1;
}
// When on the last page
if(this.currentPage === this.totalPages) {
return this.totalPages - this.maxVisibleButtons;
}
// When in between
return this.currentPage - 1;
},
pages() {
const range = [];
for(let i = this.startPage; i <= Math.min(this.startPage + this.maxVisibleButtons - 1, this.totalPages); i+=1) {
range.push({
name: i,
isDisabled: i === this.currentPage
});
}
return range;
},
isInFirstPage() {
return this.currentPage === 1;
},
isInLastPage() {
return this.currentPage === this.totalPages;
},
},
methods: {
onClickFirstPage() {
this.$emit("pagechanged", 1);
},
onClickPreviousPage() {
this.$emit("pagechanged", this.currentPage - 1);
},
onClickPage(page) {
this.$emit('pagechanged', page);
},
onClickNextPage() {
this.$emit('pagechanged', this.currentPage + 1);
},
onClickLastPage() {
this.$emit('pagechanged', this.totalPages);
},
isPageActive(page) {
return this.currentPage === page;
}
}
}
</script>
<style scoped lang="scss">
.pagination {
list-style-type: none;
}
.pagination-item {
display: inline-block;
}
.active {
background-color: #4AAE9B;
color: #ffffff;
}
</style>
my v-for with the items
<div
v-for="casino in orderBy(filteredCasinos, 'Rating', -1)"
:key="casino.id + '-filterd'"
class="casino-card"
v-show="filteredCasinos.length > 1"
>
At the moment the pagination works when I click to the next page but as I mentioned all items get shown and I want to limit them.
Use a computed property to keep track what should be visible on the current page.
With a computed property you can easily introduce a filter on the items. Then just create the functions that sets the current page, and BAM - a paginated view of items.
The snippet below does all this, and also gives the ability to choose how many items should be visible on a given page.
Advice:
new Vue({
el: "#app",
data() {
return {
posts: [],
currentPage: 1,
postsPerPage: 10,
}
},
computed: {
// computed property to set the items visible on current page
currentPagePosts() {
return this.posts.slice((this.currentPage - 1) * this.postsPerPage, this.currentPage * this.postsPerPage)
}
},
methods: {
// pagination function
setCurrentPage(direction) {
if (direction === -1 && this.currentPage > 1) {
this.currentPage -= 1
} else if (direction === 1 && this.currentPage < this.posts.length / this.postsPerPage) {
this.currentPage += 1
}
}
},
// fetching example data (200 post-like items)
async mounted() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos')
this.posts = await response.json()
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="setCurrentPage(-1)">PREV</button>
<button #click="setCurrentPage(1)">NEXT</button><br /> Current page / max page: {{ currentPage }} / {{ Math.ceil(posts.length / postsPerPage) }}<br />
<label>Set posts per page: <input v-model="postsPerPage" type="text" /></label>
<hr />
<!-- the v-for only lists items from the computed property -->
<div v-for="post in currentPagePosts" :key="post.id">
ID: {{ post.id }} Title: {{ post.title }}
</div>
</div>
I've searched and couldn't see any answer that fits what I need. I have a v-for loop with a button on each item and used VueClipboard2 to copy text. Anytime the button is clicked, I do some css changes to indicated the item that was copied. What happens is that, if there's more than 1 item, clicking on any button affects affect every other item and does the same effect.
I want to limit the clicking to the "own" item being clicked.
Here's my code:
<template>
<div class="form" id="shorten">
<form class="" #submit.prevent="shortener($event, value)">
<div>
<div class="form__shortener">
<input
class="form-input"
type="url"
name="link"
id="link"
placeholder="shorten a url here"
aria-label="input a url"
v-model="value"
/>
<button class="form-btn btn">
{{ buttonText }}
<p v-if="loading" class="loading"></p>
</button>
</div>
<SlideXLeftTransition :delay="100">
<p v-if="error" class="error">Please enter a valid link</p>
</SlideXLeftTransition>
</div>
</form>
<SlideYUpTransition group>
<div v-for="(link, index) in links" :key="index" class="form__links">
<p class="form__links-main">
{{ link.mainUrl }}
</p>
<div class="center form__links-copy">
<p>
<a :href="link.shortenedUrl" class="form__links-copy-link no-decoration">{{ link.shortenedUrl }}</a>
</p>
<button
class="form__links-copyBtn btn"
:class="[copied === true ? 'copied' : '']"
v-clipboard:copy="link.shortenedUrl"
v-clipboard:success="onCopy"
v-clipboard:error="onError"
>
<span v-if="!loading && !copied">Copy</span>
<span v-if="copied">Copied!</span>
</button>
</div>
</div>
</SlideYUpTransition>
</div>
</template>
<script>
import { required, minLength } from 'vuelidate/lib/validators';
import { SlideYUpTransition, SlideXLeftTransition } from 'vue2-transitions';
import axios from 'axios';
export default {
data() {
return {
value: '',
links: [],
message: '',
error: false,
loading: false,
buttonText: 'Shorten it!',
shortenedUrl: '',
copied: false,
};
},
validations: {
value: {
required,
minLength: minLength(1),
},
},
methods: {
async shortener(event, value) {
this.$v.$touch();
if (this.$v.$invalid) {
this.showError();
} else {
try {
this.loading = true;
this.buttonText = 'Loading';
const request = await axios.post('https://rel.ink/api/links/', { url: value });
this.loading = false;
this.buttonText = 'Shortened!';
setTimeout(() => {
this.buttonText = 'Shorten it!';
}, 1200);
this.shortenedUrl = `https://rel.ink/${request.data.hashid}`;
const mainUrl = request.data.url.length <= 20 ? request.data.url : `${request.data.url.slice(0, 30)}...`;
this.links.push({
shortenedUrl: `https://rel.ink/${request.data.hashid}`,
mainUrl,
});
localStorage.setItem('links', JSON.stringify(this.links));
} catch (error) {
this.showError();
console.log(error);
}
}
},
onCopy() {
this.copied = true;
setTimeout(() => {
this.copied = false;
}, 2500);
},
showError() {
this.error = true;
setTimeout(() => {
this.error = false;
}, 2000);
},
onError() {
alert('Sorry, there was an error copying that link. please reload!');
},
getLinks() {
if (localStorage.getItem('links')) this.links = JSON.parse(localStorage.getItem('links'));
},
},
components: {
SlideYUpTransition,
SlideXLeftTransition,
},
mounted() {
this.getLinks();
},
};
</script>
I would appreciate if anyone who help out.
Here's the live link: https://url-shortener-vue.netlify.app
To replicate, shorten two lines and click on the copy button on 1. It triggers all other items button.
Thank you.
Reason for your problem is
:class="[copied === true ? 'copied' : '']". SInce when you click any copy button, you change copied, and same class is used in all the iterations.
So, got the problem.
Solution is, you should have this copied corresponding to each link. So make your link as object.
link = [{ link: 'url...', copied: false}, {}, ...].
and, check for each link's copied value.
I am currently working on an application that involves scrolling through members from two different lists. Once you click one you see their image and bio. We added up and down arrows to scroll through their biography, but when i click the down arrow it seems that the active class on the carousel slide now jumps to the last member in my array, but still displays the member i was already on. To add to that I cannot swipe back and forth once i am on a member (this is something that I could do previously.) I know this probably isn't the best description and there is only so much code I can show, as I cannot display the entire application.
I wanted to also note that if I refresh my page, everything works as expected. Does this mean something isn't initializing correctly?
this is the code specific to the page i am talking about:
<template>
<div class="member-info-carousel">
<div class="header">
<h2 v-if="founderChairman === true">Member List One</h2>
<h2 v-else>Member List Two</h2>
<img src="../assets/logo.png" alt="Logo" />
</div>
<carousel :minSwipeDistance="384" :perPage="1" :paginationEnabled="false" :navigationEnabled="true" navigationNextLabel="<i>NEXT</i>"
navigationPrevLabel="<i>BACK</i>" :navigateTo="selectedListIndex" #pagechange="OnPageChange">
<slide v-for="(member, index) in selectedList" :key="index">
<div class="member-bio-page" :member="member" v-on:showContent="showContent">
<div class="bio">
<div class="portrait-image">
<img :src="member.imgSrc" />
</div>
<div class="bio-container">
<div class="inner-scroll" v-bind:style="{top: scrollVar + 'px'}">
<div class="english"></div>
<div class="pin-name">
<img :src="member.pin" />
<h1>{{ member.name }}</h1>
</div>
<div class="description-container">
<div class="para">
<p class="quote" v-html="member.quote"></p>
<p v-html="member.bio"></p>
<div class="spanish"></div>
<p class="quote" v-html="member.spanishQuote"></p>
<p v-html="member.spanishBio"></p>
</div>
</div>
</div>
</div>
<div class="scroll-buttons">
<div>
<!-- set the class of active is the scroll variable is less than 0-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar < 0 }" #click="scrollUp" src="#/assets/arrow-up.png">
</div>
<div>
<!-- set the class of active is the scroll variable is greater than the height of the scrollable inner container-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar > pageChangeHeight }" #click="scrollDown" src="#/assets/arrow-down.png">
</div>
</div>
<div class="eng-span">
English
Español
</div>
</div>
<div class="play-button">
<!-- if the array members has a property of video, then the play button will show on the slide. If not it will not show the image -->
<img v-if="member.hasOwnProperty('video')" #click="showContent" src="#/assets/play-button.png">
</div>
</div>
<!-- <MemberBioPage :member="member" v-on:showContent="showContent"/> -->
</slide>
</carousel>
<modal name="video-modal"
:width="1706"
:height="960">
<video width="1706" height="960" :src="(selectedList && selectedList[this.currentPage]) ? selectedList[this.currentPage].video : ''" autoplay />
</modal>
<div class="footer-controls">
<div class="footer-bar">
<p>Tap Back or Next to view additional profiles.</p>
<p>Tap the arrows to scroll text up or down.</p>
</div>
<div class="nav-container">
<img class="nav-bubble" src="#/assets/navigation-bubble-bio-page.png" alt="An image where the back, next and close button sit" />
</div>
<button class="close-button" #click="closeInfo">
<img src="#/assets/x-close-button.png" />
CLOSE
</button>
</div>
</div>
</template>
<script>
import { Carousel, Slide } from 'vue-carousel'
export default {
data () {
return {
currentPage: 0,
pageChangeHeight: -10,
scrollVar: 0
}
},
components: {
// MemberBioPage,
Carousel,
Slide
},
mounted () {
this.enableArrows()
},
updated () {
this.enableArrows()
},
computed: {
selectedList () {
return this.$store.state.selectedList
},
selectedListIndex () {
return this.$store.state.selectedListIndex
},
founderChairman () {
return this.$store.state.founderChairman
}
},
methods: {
enableArrows () {
var outerHeight
var innerHeight
if (document.querySelectorAll('.VueCarousel-slide-active').length > 0) {
outerHeight = document.querySelectorAll('.VueCarousel-slide-active .bio-container')[0].clientHeight
innerHeight = document.querySelectorAll('.VueCarousel-slide-active .inner-scroll')[0].clientHeight
} else {
outerHeight = document.querySelectorAll('.VueCarousel-slide .bio-container')[0].clientHeight
innerHeight = document.querySelectorAll('.VueCarousel-slide .inner-scroll')[0].clientHeight
}
this.pageChangeHeight = outerHeight - innerHeight
return this.pageChangeHeight
},
scrollUp () {
this.scrollVar += 40
console.log(this.scrollVar += 40)
},
scrollDown () {
this.scrollVar -= 40
console.log(this.scrollVar)
},
OnPageChange (newPageIndex) {
this.scrollVar = 0
this.currentPage = newPageIndex
this.pageChangeHeight = -10
},
closeInfo () {
if (this.$store.state.selectedList === this.$store.state.foundersList) {
this.$store.commit('setSelectedState', this.$store.state.foundersList)
this.$router.push({ name: 'Carousel' })
} else if (this.$store.state.selectedList === this.$store.state.chairmanList) {
this.$store.commit('setSelectedState', this.$store.state.chairmanList)
this.$router.push({ name: 'Carousel' })
}
},
showContent () {
this.$modal.show('video-modal')
},
toEnglish () {
this.scrollVar = 0
},
toSpanish () {
var spanishPos
if (document.querySelectorAll('.VueCarousel-slide-active').length > 0) {
spanishPos = document.querySelectorAll('.VueCarousel-slide-active .spanish')[0].offsetTop
} else {
spanishPos = document.querySelectorAll('.VueCarousel-slide .spanish')[0].offsetTop
}
this.scrollVar = -spanishPos
}
}
}
</script>
This is my store index file:
import Vue from 'vue'
import Vuex from 'vuex'
import chairmans from '#/data/chairmans-club'
import founders from '#/data/founders-circle'
import memoriam from '#/data/in-memoriam'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
finishedLoading: false,
transitioning: false,
foundersList: founders,
chairmanList: chairmans,
selectedList: founders,
selectedListIndex: -1,
founderChairman: true,
inMemoriam: memoriam,
idleTimer: {
id: null,
duration: 1
},
idleTimeoutModal: {
show: false,
duration: 1
}
},
mutations: {
setSelectedState (state, list) {
state.selectedList = list
},
setSelectedListIndex (state, idx) {
state.selectedListIndex = idx
},
showIdleTimeoutModal (state, value) {
state.idleTimeoutModal.show = value
},
founderChairmanClicked (state, data) {
state.founderChairman = data
},
setInMemoriam (state, content) {
state.inMemoriam = content
}
},
actions: {
restartIdleTimer ({ state, commit }) {
clearTimeout(state.idleTimer.id)
state.idleTimer.id = setTimeout(() => {
commit('showIdleTimeoutModal', true)
}, state.idleTimer.duration * 1000)
},
stopIdleTimer ({ state }) {
clearTimeout(state.idleTimer.id)
}
}
})
export default store
and an example of the data i am pulling:
const event = [
{
index: 0,
name: 'Member Name',
carouselImage: require('#/assets/carousel-images/image.jpg'),
drawerImage: require('#/assets/drawer-images/drawerimage.jpg'),
imgSrc: require('#/assets/bio-images/bioimage.jpg'),
quote: '“quote.”',
spanishQuote: `“spanish quote.”`,
bio: '<p>bio copy here</p>',
spanishBio: '<p>spanish bio copy</p>',
pin: require('#/assets/pin.png')
}
]
export default event
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