multiple dynamic countdown timers vue js on laravel - vuejs2

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

How to display loaded data after page refresh in vue, the data is displayed in the console but not in theview

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

Vue el-form dynamic validation

<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.

How to transfer post from one component to another?

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?

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

Pagination. How to make moving between pages by clicking on numerals

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