Why currentPage does not do anything in Vue - vue.js

I am creating a paginator it does not display any error but when I click in the button 1 or 2 or 3 etc, it does not do anything so I wonder why not.
My component template code:
<v-pagination v-model="currentPage"
:page-count="total"
:classes="bootstrapPaginationClasses"
:labels="paginationAnchorTexts"
></v-pagination>
My script code:
export default {
created() {
this.getPosts();
},
methods: {
getPosts() {
fetch('/api/bank?page='+this.currentPage)
.then(response => response.json() )
.then(
json => {
this.posts = json.data.data;
this.total = json.data.last_page;
this.currentPage = json.data.current_page;
});
}
},
components: { vPagination },
data: function() {
return {
postsSelected: "",
posts: [],
currentPage: 1,
total: 0,
bootstrapPaginationClasses: {
ul: 'pagination',
li: 'page-item',
liActive: 'active',
liDisable: 'disabled',
button: 'page-link'
},
paginationAnchorTexts: {
first: 'Primera',
prev: '«',
next: '»',
last: 'Última'
}
}
}
}
So if I have in the function getPosts(); the value this.currentPage it automaticly will send the current page, but when I click in 1 or 2 or 3 etc nothing happens, it just display 1 and nothing else, it does not display 1 several times just one time, so I think that I miss something which it fires something that it notifies that I am pushing the paginator button.
what do I miss?
Thanks!

Because you do nothing when currentPage change. You can listen on input event and then call getPosts.
Example:
<v-pagination
v-model="page"
#input='getPosts'>
</v-pagination>
JSFiddle

Related

Countdown timer doesn't display when a new timeout props pass. How to fix it?

I want to make a special component which handles failed fetch requests. It is expected to work in this way:
If fetch request fails then several more attempts should be made after several seconds.
This special component should display countdown timer for next request to launch.
So I have:
Fetch function is in store. It works fine (makes 3 requests after 3, 6 and 9 seconds).
import { createStore } from "vuex";
const wait = async (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
};
export default createStore({
state: {
error: {
isError: false,
timerSec: null
}
},
mutations: {
setError(state, payload) {
state.error = payload.error;
}
},
actions: {
async fetchProducts({ commit, dispatch }, attempt = 1) {
try {
const response = await fetch("https://fakestoreapi.com/products222");
if (!response.ok) {
throw new Error("Something went wrong");
}
} catch (e) {
console.log("Request:", attempt);
commit("setError", {
error: {
isError: true,
timerSec: attempt * 3
}
});
if (attempt >= 3) {
return;
}
await wait(attempt * 3000);
return dispatch("fetchProducts", attempt + 1);
}
}
}
});
I call fetchProducts() in App.vue on mount. In App.vue I pass following data to error-request component:
<template>
<error-request v-if="error.isError" :timeout="error.timerSec"></error-request>
<h1 v-else>This should be rendered if there's no errors</h1>
</template>
In the error-request component I have a countDown method which triggered when timeout props changes.
<template>
<div>
<h1>The next attempt to fetch data will be made in:</h1>
<h2>{{ timer }}</h2>
</div>
</template>
<script>
export default {
props: ["timeout"],
data() {
return {
timer: null,
interval: null,
};
},
methods: {
countDown(sec) {
this.interval = setInterval(() => {
this.timer = sec;
if (sec === 0) {
clearInterval(this.interval);
return;
}
sec--;
}, 1000);
},
},
watch: {
timeout() {
this.countDown(this.timeout);
},
},
};
</script>
Unfortunatelly countdown timer shows only once and only on second request (it ignores first request with countdown from 3 to 1 and ignores third request. Could you help me to fix it?
I made a codesandbox: https://codesandbox.io/s/peaceful-sinoussi-ozjkq8?file=/src/App.vue
You should do:
methods: {
countDown(sec) {
this.timer = sec;
this.interval = setInterval(() => {
this.timer--;
if (this.timer === 0) {
clearInterval(this.interval);
return;
}
}, 1000);
},
},
watch: {
timeout: {
handler() {
this.countDown(this.timeout);
},
immediate: true,
},
},
There are 2 points to notice:
Don't modify the function parameters to prevent side effects (In your case is the sec parameter)
You have to trigger the watch for the first time so you need to add the option immediate: true

nuxt buefy filter is not working in taginput field

I am using buefy taginput in my form, everything works as expect filter using ontype event.
only problem here is that i can see data in taginput box on when i focus, its getting selected too, but when i type its not getting filtered. for 10-15 items its not a problem but when its 1000+ items, it will be difficult. i don't know whats the problem here.
here is code so far.
<template>
<b-field label="Popular Destinations">
<b-taginput
v-model="form.popularSubDests"
:data="allSubDests"
autocomplete
:allow-new="allowNew"
:open-on-focus="openOnFocus"
field="SubDestName"
icon="label"
placeholder="Add Cities"
#typing="getFilteredSubdest"
>
</b-taginput>
</b-field>
</template>
<script>
export default {
data() {
return {
openOnFocus: false,
isSelectOnly: false,
allowNew: false,
allSubDestinations: [],
form: {
popularSubDests: [
{
SubDestName: null,
SubDestId: null,
},
],
},
}
},
computed: {
allSubDests() {
return this.allSubDestinations.map((item) => ({
SubDestId: item.id,
SubDestName: item.subdestname,
}))
},
},
methods: {
getFilteredSubdest(text) {
this.allSubDests = this.allSubDests.filter((option) => {
return option.SubDestName.toString().toLowerCase().indexOf(text.toLowerCase()) >= 0
})
},
},
async asyncdata({ route }) {
let { data: allSubDest } = await axios.get(`process.env.FETCHSUBDEST`)
return {
allSubDestinations: allSubDest.results,
}
},
}
</script>

Vue2 set a variable from an api callback

I have this function return a call back as:
function fetchShifts(ctx, callback) {
const accountId = selectedAccount.value.value.id
store.dispatch('app-action-center/fetchShifts', {
accountId,
})
.then(shifts => {
const data = []
shifts.forEach(async (shift, index) => {
const user = await store.dispatch('app-action-center/fetchUserDetails',
{
assignedTo: shift.assignedTo,
})
.then(res => res)
data.push({
...shift,
user: user.fullName,
})
if (index === (shifts.length - 1)) { callback(data) }
})
})
}
In the vue file I try to set it as:
data() {
return {
shifts: this.fetchShifts,
}
},
or
data() {
return {
shifts: null,
}
},
created() {
this.shifts = this.fetchShifts()
}
None of them work, I want to make this shifts variable ready when the component mounted so I can put it in the <app v-for="shift in shifts" />
At this moment, this code work fine with <b-table :items="fetchShifts /> but I don't know how to convert to <ul v-for="shift in shifts></ul>
Try like this:
<ul v-for="shift in shifts" :key="shift.id">
</ul>
export default
{
data()
{
return {
shifts: [],
};
},
created()
{
this.fetchShifts(undefined, (shiftsArray) =>
{
this.shifts = shiftsArray;
});
}
}
Explanation - initially you start with an empty array. Then you asynchronously fetch the shifts. The callback is called as soon as all the shifts and the corresponding users have been fetched - and in this callback you update the array with the shifts, which in turn triggers component re-rendering.
Vue is truly amazing!

Nuxtjs auto log out user inactive

I'm using Nuxtjs for my project. I need to logout the user if there is not active after a given time frame. I'm creating a new component name autologout.vue and add this code to it
autologout.vue
<template>
<div>
hello
<div v-if="warningZone">warning</div>
</div>
</template>
<script>
export default {
data() {
return {
events: ['click', 'mousemove', 'mousedown', 'scroll', 'keypress', 'load'],
warningTimer: null,
logoutTimer: null,
warningZone: false,
}
},
mounted() {
this.events.forEach(function (event) {
window.addEventListener(event, this.resetTimer())
}, this)
this.setTimers()
},
destroyed() {
this.events.forEach(function (event) {
window.removeEventListener(event, this.resetTimer())
}, this)
this.resetTimer()
},
methods: {
setTimers() {
this.warningTimer = setTimeout(this.warningMessage(), 4 * 1000)
this.logoutTimer = setTimeout(this.logoutuser(), 10 * 1000)
this.warningZone = false
},
warningMessage() {
this.warningZone = true
},
logoutuser() {
this.$auth.logout('local').then((data) => {
console.log(data)
})
},
resetTimer() {
clearTimeout(this.warningTimer)
clearTimeout(this.logoutTimer)
this.setTimers()
},
},
}
</script>
<style></style>
add import this component to layout->default.vue. I'm not using default.vue layout to my login page. after I'm login and redirect to the home page it always logout me. What is wrong?
I'm using this tutorial to implement this
Tutorial link
Although it is not a perfect way to handle the problem, but if you remove the parentheses present inside the addEventListener function, it will start working.
Change
window.addEventListener(event, this.resetTimer())
To
window.addEventListener(event, this.resetTimer)
And if you remove the paratheses from removeEventListener, it will again stop working. Don't know why.

Detect vuex state change to execute a method inside a nuxt layout

I am trying to show vuetify snackbar alert, once I completed a form submission inside a page or vue component. I use vuex store to manage alert type and message.
my-nuxt-app/store/alerts.js
export const state = () => ({
message: '',
type: ''
});
export const getters = {
hasAlert(state) {
return state.message !== '';
},
alertMessage(state) {
return state.message;
},
alertType(state) {
return state.type;
}
};
export const mutations = {
SET_ALERT(state, payload) {
state.type = payload.type;
state.message = payload.message;
}
};
export const actions = {
setAlert({commit}, payload) {
commit('SET_ALERT', payload);
},
clearAlert({commit}) {
commit('SET_ALERT', {});
}
};
And I created a nuxt plugin to access getters globally in my application.
my-nuxt-app/plugins/alert.js
import Vue from 'vue';
import {mapGetters} from 'vuex';
const Alert = {
install(Vue, options) {
Vue.mixin({
computed: {
...mapGetters({
hasAlert: 'alerts/hasAlert',
alertType: 'alerts/alertType',
alertMessage: 'alerts/alertMessage'
})
}
});
}
};
Vue.use(Alert);
Inside my AccountForm component submit method, I am dispatching my alert information to store like below.
my-nuxt-app/components/form/AccountForm.vue
...
methods: {
async submit () {
try {
await this.$axios.patch("/settings/profile", this.form);
this.$store.dispatch('alerts/setAlert', {
type: 'success',
message: 'You have successfully updated your information.'
});
} catch (e) {
}
}
},
...
}
...
And this AccountForm.vue component is a child component of profile.vue page which is obviously inside the pages folder of my project. And also I have extended the dashboard.vue layout to this profile.vue page and to the most of the pages inside my pages directory as a common layout. Hence, I added the snackbar component into dashboard layout to show a alert message whenever required.
my-nuxt-app/layouts/dashboard.vue
<template>
...
<v-snackbar
:timeout="snackbar.timeout"
:color="snackbar.color"
:top="snackbar.y === 'top'"
:bottom="snackbar.y === 'bottom'"
:right="snackbar.x === 'right'"
:left="snackbar.x === 'left'"
:multi-line="snackbar.mode === 'multi-line'"
:vertical="snackbar.mode === 'vertical'"
v-model="snackbar.show"
>
{{ snackbar.text }}
<v-btn flat icon dark #click.native="snackbar.show = false">
<v-icon>close</v-icon>
</v-btn>
</v-snackbar>
...
</template>
<script>
...
data: () => ({
snackbar: {
show: false,
y: 'top',
x: null,
mode: '',
timeout: 6000,
color: '',
text: ''
},
}),
computed: {
availableAlert: function () {
return this.hasAlert;
}
},
watch: {
availableAlert: function(alert) {
if(alert) {
this.showAlert(this.alertType, this.alertMessage);
this.$store.dispatch('alerts/clearAlert');
}
}
},
methods: {
showAlert(type, message) {
this.snackbar.show = true;
this.snackbar.color = type;
this.snackbar.text = message;
}
}
</script>
I am getting the alert message for the first time submission of the form and after that I have to reload the page and then submit to get the alert. Please enlighten me a way to detect the vuex state change and trigger showAlert method inside the dashboard.vue accordingly.
It's most likely the way you're checking hasAlert
Your clearAlert passes an empty object, your setAlert is trying to assign properties of that empty object, while your hasAlert is checking if it's an empty string.
If you change your clearAlert to:
clearAlert({commit}) {
commit('SET_ALERT', { message: '', type: '' });
}
That should fix your issue.