I would like to have a countdown timer for each of my auction items, these auctions can and will be loaded dynamically.
Ideally {{ auction.total_bids }} would be the countdown, this will need to be reset to a value i can set on a click event.
My code so far, is as followed:
<template>
<div>
<h1>Live Auctions</h1>
<ul class="row">
<li class="col-lg-4" v-for="(auction, key, index) in auctions" :key="auction.id">
<span>{{ auction.name }} ({{ auction.id }})</span><br />
<span ref="bitTime">{{ auction.bid_time }}</span><br />
<span ref="totalBids">{{ auction.total_bids }}</span><br />
<span ref="user">{{ auction.username }}</span><br />
<button ref="newBid" #click="bidOnThis(auction.id, key)">Bid on this item</button>
</li>
</ul>
</div>
</template>
<script>
export default {
props : {
date : {
type: Number,
coerce: str => Math.trunc(Date.parse(str) / 1000)
}
},
data() {
return {
auctions: [],
newBid: '',
totalBids: '',
user: []
};
},
created() {
axios.get('/auctions').then(result => {
this.auctions = result.data
});
axios.get('/getuser').then(result => {
this.user = result.data;
});
window.Echo.channel('auction').listen('AuctionUpdated', ({ auction, username, key }) => {
this.$refs.totalBids[key].innerHTML = parseInt(this.$refs.totalBids[key].innerHTML) + 1 ;
this.$refs.user[key].innerHTML = username ;
});
},
methods: {
bidOnThis(id, key) {
axios.post('/auctions', { id: id, key: key });
this.$refs.totalBids[key].innerHTML = parseInt(this.$refs.totalBids[key].innerHTML) + 1 ;
this.$refs.user[key].innerHTML = this.user.username ;
}
}
};
Related
I'm loading notifications from an api using get request, the data is there i can see it in the console but it's not displayed in the view here is my code :
<!-- Header -->
<li class="dropdown-menu-header">
<div class="dropdown-header d-flex">
<h4 class="notification-title mb-0 mr-auto">
Notifications
</h4>
<b-badge pill variant="light-primary">
{{ notifications.length }} New
</b-badge>
</div>
</li>
<!-- Notifications -->
<vue-perfect-scrollbar v-once :settings="perfectScrollbarSettings" class="scrollable-container media-list scroll-area" tagname="li">
<!-- Account Notification -->
<b-link v-for="notification in notifications" :key="notification.id">
<b-media>
<template #aside>
<b-avatar size="32" :src="require('#/assets/images/avatars/6-small.png')" :text="notification.id" :variant="notification.type" />
</template>
<p class="media-heading">
<span class="font-weight-bolder">
{{ notification.data.message }}
</span>
</p>
<small class="notification-text">{{ notification.created_at | formatDate}}</small>
</b-media>
</b-link>
</vue-perfect-scrollbar>
here is the method :
data() {
return {
notifications: []
}
},
mounted() {
this.getNotifications();
},
methods: {
getNotifications() {
axios.get(apiHost + '/notification')
.then((response) => {
for (let i = 0; i < response.data.length; i++) {
this.notifications.push(response.data[i])
}
console.log(this.notifications)
})
.catch(resonse => {
console.log(resonse);
})
},
},
I just get the length of the array but i can t display the data:
please try just this:
data() {
return {
notifications: []
}
},
async mounted() {
await this.getNotifications();
},
methods: {
async getNotifications() {
await axios.get(apiHost + '/notification')
.then((response) => {
this.notifications = response.data
}
})
.catch(resonse => {
console.log(resonse);
})
},
},
otherwise please show us the response from the api, if you like mocked of course
<template>
<div>
<el-form label-position="top" :model="notificationEmails" ref="emailForm">
<el-form-item
v-for="(item, index) in notificationEmails.emails"
:key="index"
:label="getLabel(index)"
:for="`${item.id}_${index}`"
:prop="'emails.' + index + '.id'"
:rules="{
required: true,
type: 'email',
message: 'Not valid email',
trigger: ['blur', 'change']
}"
>
<el-row>
<el-col :span="6">
<el-input v-model="item.id" type="email" :id="`${item.id}_${index}`" />
</el-col>
<el-col :span="2" style="padding-left: 18px">
<span v-if="index === 0" tabindex="0" #click="addEmail" #keyup.enter.stop="addEmail">
<i aria-hidden="true" class="icon-add-circle-outline" />
<span class="screen-reader">{{$t('a11y.settings.soldTo.notif.action.addEmail')}}</span>
</span>
<span
v-else
tabindex="0"
#click="deleteEmail(item.id)"
#keyup.enter.stop="deleteEmail(item.id)"
>
<i class="icon-subtract-circle-outline" aria-hidden="true" />
<span class="screen-reader">{{$t('a11y.settings.soldTo.notif.action.deleteEmail')}}</span>
</span>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'EmailWidget',
data() {
return {
notificationEmails: {
emails: []
}
};
},
props: ['passEmail'],
watch: {
passEmail: {
handler(newVal) {
this.notificationEmails.emails = newVal;
},
deep: true
},
notificationEmails: {
handler() {
this.$refs.emailForm.validate(async validate => {
if (validate) {
await this.$store.dispatch('settings/GENERIC', {
module: 'common',
propKey: 'validEmail',
propValue: true
});
} else {
await this.$store.dispatch('settings/GENERIC', {
module: 'common',
propKey: 'validEmail',
propValue: false
});
}
});
},
deep: true
}
},
methods: {
addEmail() {
this.notificationEmails.emails.push({
id: '',
priority: this.notificationEmails.emails.length + 1
});
// this.emails = [...this.emails, { id: '', priority: this.emails.length + 1 }];
},
deleteEmail(email) {
// this.emails = this.emails.filter(item => item.id !== email);
let index = 0;
for (let i = 0; i < this.notificationEmails.emails.length; i += 1) {
if (this.notificationEmails.emails[i].id === email) {
index = i;
break;
}
}
this.notificationEmails.emails.splice(index, 1);
},
getLabel(index) {
return index === 0 ? this.$t('settings.soldTo.notif.email') : '';
}
},
};
</script>
<style lang="scss">
i:hover {
cursor: pointer;
}
</style>
Some problems about the validation in dynamic add or delete the emails in el-form of Vue. When I add a new email, the validation cannot work. When I delete email. it shows
Error: please transfer a valid prop path to form item!
There is no issue when I edit the email.
I change the props according to enter code here the official document, but it still shows error.
Good afternoon, please tell me. I am training now using Vuex and I cannot transfer the post from one component to another. I have a component Pagination, where all the posts and the history component are stored where and should send the first 5 posts that I click on to visit them. That is, it should work approximately as a history of viewing posts. I wrote some code here, but my posts are not displayed, tell me what I'm doing wrong and how to fix it.
Component code where all posts are stored:
<template>
<div class = "app">
<ul>
<li v-for="(post, index) in paginatedData" class="post" :key="index">
<router-link :to="{ name: 'detail', params: {id: post.id, title: post.title, body: post.body} }" #click="addPostToHistoryComp(post.id, post.title, post.body)">
<img src="src/assets/nature.jpg">
<p class="boldText"> {{ post.title }}</p>
</router-link>
<p> {{ post.body }}</p>
</li>
</ul>
<div class="allpagination">
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<div class="pagin">
<button class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}"
#click="page=n-1">{{ n }} </button>
</div>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
name: 'app',
data () {
return {
current: null,
page: 0,
visiblePostID: '',
}
},
mounted(){
this.$store.dispatch('loadPosts')
},
computed: {
posts(){
return this.$store.state.posts
},
search(){
return this.$store.state.sSearch
},
evenPosts: function(posts){
return Math.ceil(this.posts.length/6);
},
paginatedData() {
const start = this.page * 6;
const end = start + 6;
return this.filteredPosts.slice(start, end);
},
filteredPosts() {
return this.posts.filter((post) => {
return post.title.match(this.search);
});
},
},
methods: {
addPostToHistoryComp(val){
this.$store.dispatch('transforPostToHistoryComp', { // как вызвать actions с объект с параметром
pTitle: val.post.title,
pBody: val.post.body,
pId: val.post.id
})
},
}
}
</script>
The code of the History component where the last 5 posts that were opened should be displayed:
<template>
<div class="history">
<ul>
<li v-for="(historyPost, index) in historyPosts" class="post" :key="index">
<img src="src/assets/nature.jpg">
<p class="boldText"> {{ post.title }}</p>
<p> {{ post.body }}</p>
</li>
</ul>
</div>
</template>
<script>
export default{
computed: {
historyPosts(){
return this.$store.state.historyPosts
},
},
}
</script>
And the code of my story (Vuex):
export default new vuex.Store({
state: {
posts: [],
sSearch: '',
title: '',
body: '',
id: Number,
historyPosts: []
},
actions: {
loadPosts ({commit}) {
axios.get('http://jsonplaceholder.typicode.com/posts').then(response => {
let posts = response.data
commit('SET_POSTS', posts)
}).catch(error => {
console.log(error);
})
},
transforTitleAndBody({commit}, payload){ // мутация которая изменяет сосотаяние в sSearch
const todo = {
title: payload.sTitle,
body: payload.sBody,
id: payload.sId
}
axios.post('http://jsonplaceholder.typicode.com/posts', todo).then(_ => {
commit('ADD_TODO', todo)
}).catch(function (error) {
console.log(error);
})
},
transforPostToHistoryComp({commit}, payload){ // мутация которая изменяет сосотаяние в sSearch
const todohistory = {
title: payload.pTitle,
body: payload.pBody,
id: payload.pId
}
commit('ADD_TODO_HISTORY', todohistory)
}
},
mutations: {
SET_POSTS(state, posts) {
state.posts = posts
},
transforSearch(state, payload){ // мутация которая изменяет сосотаяние в sSearch
state.sSearch = payload
},
ADD_TODO (state, todoObject) {
state.posts.unshift(todoObject)
},
ADD_TODO_HISTORY (state, todohistoryObject) {
state.historyPosts.unshift(todohistoryObject)
},
},
})
I found what happening. You have some erros on code of the file Pagination.vue
You was putting #click under <router-link>, that doesn't work because router link change the page with preventing effect any other event before leave.
I made some changes on template and script. I think will work.
<template>
<div class="app">
<ul>
<template v-for="(post, index) in paginatedData">
<li class="post" :key="index" #click="addPostToHistoryComp(post)">
<img src="src/assets/nature.jpg">
<p class="boldText">{{ post.title }}</p>
<p>{{ post.body }}</p>
</li>
</template>
</ul>
<div class="allpagination">
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<div class="pagin">
<button
class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}"
#click="page=n-1"
>{{ n }}</button>
</div>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "app",
data() {
return {
current: null,
page: 0,
visiblePostID: ""
};
},
mounted() {
this.$store.dispatch("loadPosts");
},
computed: {
posts() {
return this.$store.state.posts;
},
search() {
return this.$store.state.sSearch;
},
evenPosts: function(posts) {
return Math.ceil(this.posts.length / 6);
},
paginatedData() {
const start = this.page * 6;
const end = start + 6;
return this.filteredPosts.slice(start, end);
},
filteredPosts() {
return this.posts.filter(post => {
return post.title.match(this.search);
});
}
},
methods: {
addPostToHistoryComp(post) {
this.$store.dispatch("transforPostToHistoryComp", {
pTitle: post.title,
pBody: post.body,
pId: post.id
});
this.$router.push({
name: "detail",
params: { id: post.id, title: post.title, body: post.body }
});
}
}
};
</script>
How to make pagination. I tried many times already, but I can’t do it. I have to paginate without Laravel. The problem is that I can not make a cycle that will display the number of pages, each page should have 10 posts, and there are 98 posts in total. I made the property to be calculated, thanks to which you can find out how many pages there will be. I made a page switch that works. But for some reason, the cycle with which I will display the number of pages does not work for me, I cannot understand what the problem is?
Screenshot
My Vue js:
import axios from 'axios';
export default {
name: 'app',
data () {
return{
counter: 1,
zero: 0,
posts: [],
createTitle: '',
createBody: '',
visiblePostID: '',
}
},
watch: {
counter: function(newValue, oldValue) {
this.getData()
}
},
created(){
this.getData()
},
computed: {
evenPosts: function(posts){
return Math.ceil(this.posts.length/10);
}
},
methods: {
getData() {
axios.get(`http://jsonplaceholder.typicode.com/posts?_start=${this.counter}+${this.zero}&_limit=10`).then(response => {
this.posts = response.data
})
},
// even: function(posts) {
// return Math.ceil(this.posts.length/10)
// },
deleteData(index, id) {
axios.delete('http://jsonplaceholder.typicode.com/posts/' + id)
.then(response => {
console.log('delete')
this.posts.splice(index, 1);
})
.catch(function(error) {
console.log(error)
})
},
addPost() {
axios.post('http://jsonplaceholder.typicode.com/posts/', {
title: this.createTitle,
body: this.createBody
}).then((response) => {
this.posts.unshift(response.data)
})
},
changePost(id, title, body) {
axios.put('http://jsonplaceholder.typicode.com/posts/' + id, {
title: title,
body: body
})
},
},
}
My html:
<div id="app">
<div class="smallfon">
<div class="blocktwitter"><img src="src/assets/twitter.png" class="twitter"/></div>
<div class="addTextPost">Add a post</div>
<input type="text" v-model="createTitle" class="created"/>
<input type="text" v-model="createBody" class="created"/>
<div><button #click="addPost()" class="addPost">AddPost</button></div>
<div class="post1">
<div class="yourPosts">Your Posts</div>
<ul>
<li v-for="(post, index) of posts" class="post">
<p><span class="boldText">Title:</span> {{ post.title }}</p>
<p><span class="boldText">Content:</span> {{ post.body }}</p>
<button #click="deleteData(index, post.id)" class="buttonDelete">Delete</button>
<button #click="visiblePostID = post.id" class="buttonChange">Change</button>
<div v-if="visiblePostID === post.id" class="modalWindow">
<div><input v-model="post.title" class="changePost"><input v-model="post.body" class="changePost"></div>
<button type="button" #click="changePost(post.id, post.title, post.body)" class="apply">To apply</button>
</div>
</li>
</ul>
<button type="button" #click="counter -=1" class="prev">Предыдущая</button>
<!-- <div class="counter">{{ counter }}</div> --> <span v-for="n in evenPosts" :key="n.id">{{ n }} </span>
<button type="button" #click="counter +=1" class="next">Следущая</button>
<!-- <span v-for="n in evenPosts" :key="n.id">{{ n }} </span> -->
</div>
</div>
</div>
If you bind a limit to your fetching request (axios.get(...&_limit=10)), you can't return a paginate count because your computed evenPost property will always return 1 i.e Math.ceil(10/10) == 1
To fix your pagination, remove the parameters query to get the data:
getData() {
axios.get('https://jsonplaceholder.typicode.com/posts').then(response => {
this.posts = response.data
})
}
Then change the default counter page to 0 and add a computed property to return 10 posts based on it:
data () {
return {
counter: 0,
//...
}
},
computed: {
paginatedPosts() {
const start = this.counter * 10;
const end = start + 10;
return this.posts.slice(start, end);
}
}
Now you can iterate on this property:
<ul>
<li v-for="(post, index) of paginatedPosts" class="post">
...
</li>
</ul>
Basic live example
Tell me how to make it so that when you click on a button from a cycle with page numbers, this particular page opens. Switching along the arrows works for me, but I cannot understand how to switch between pages. I take data from Api. Total posts 98. It is possible to add your posts. On one page only 10 posts are shown.
My html:
<div id="app">
<div class="smallfon">
<div class="blocktwitter"><img src="src/assets/twitter.png" class="twitter"/></div>
<div class="addTextPost">Add a post</div>
<input type="text" v-model="createTitle" class="created"/>
<input type="text" v-model="createBody" class="created"/>
<div><button #click="addPost()" class="addPost">AddPost</button></div>
<div class="post1">
<div class="yourPosts">Your Posts</div>
<ul>
<li v-for="(post, index) of paginatedData" class="post">
<p><span class="boldText">Title:</span> {{ post.title }}</p>
<p><span class="boldText">Content:</span> {{ post.body }}</p>
<button #click="deleteData(index, post.id)" class="buttonDelete">Delete</button>
<button #click="visiblePostID = post.id" class="buttonChange">Change</button>
<div v-if="visiblePostID === post.id" class="modalWindow">
<div><input v-model="post.title" class="changePost"><input v-model="post.body" class="changePost"></div>
<button type="button" #click="changePost(post.id, post.title, post.body)" class="apply">To apply</button>
</div>
</li>
</ul>
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<button class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}">{{ n }} </button>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</div>
My js:
export default {
el: "#app",
data () {
return {
current: null,
page: 0,
posts: [],
createTitle: '',
createBody: '',
visiblePostID: '',
}
},
watch: {
counter: function(newValue, oldValue) {
this.getData()
}
},
created(){
this.getData()
},
computed: {
evenPosts: function(posts){
return Math.ceil(this.posts.length/10);
},
paginatedData() {
const start = this.page * 10;
const end = start + 10;
return this.posts.slice(start, end);
}
},
methods: {
setCurrent: function(id) {
this.current = id;
},
getData() {
axios.get(`https://jsonplaceholder.typicode.com/posts`).then(response => {
this.posts = response.data
})
},
deleteData(index, id) {
axios.delete('http://jsonplaceholder.typicode.com/posts/' + id)
.then(response => {
console.log('delete')
this.posts.splice(index, 1);
})
.catch(function(error) {
console.log(error)
})
},
addPost() {
axios.post('http://jsonplaceholder.typicode.com/posts/', {
title: this.createTitle,
body: this.createBody
}).then((response) => {
this.posts.unshift(response.data)
})
},
changePost(id, title, body) {
axios.put('http://jsonplaceholder.typicode.com/posts/' + id, {
title: title,
body: body
})
},
}
}
Screenshot of application
add click event #click="page=n" in button
<button #click="page=n" class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}">{{ n }} </button>
Codepen : https://codepen.io/anon/pen/bZOROO