Nuxt pagination with asyncData - vue.js

It's possible to does a pagination with asyncData in nuxt?
I have this code:
<template>
<v-container fluid>
<v-row>
<v-col
v-for="sessao in sessoes"
:key="sessao.id"
xs="12"
sm="12"
md="6"
lg="4"
>
<FotografoSessao :sessao="sessao" :is-mostrar-titulo="true" />
</v-col>
</v-row>
<v-row>
<v-container class="max-width">
<v-pagination
v-model="paginaAtual"
:length="totalPages"
:total-visible="10"
#input="proximo"
></v-pagination>
</v-container>
</v-row>
</v-container>
</template>
<script>
export default {
async asyncData({ $api, store, route }) {
let url = "/sessao/ultimas";
if (store.state.auth.isLogged) {
url = "/sessao/praias/usuario";
}
const page = parseInt(route.query.page);
const retorno = await $api.get(`${url}?page=${page - 1}`);
return {
sessoes: retorno.data.content,
totalPages: retorno.data.totalPages,
totalItems: retorno.data.content.totalItems,
paginaAtual: parseInt(page),
};
},
data() {
return {};
},
watchQuery: ["page"],
methods: {
proximo(val) {
const page = parseInt(val);
this.$router.push({ path: this.$route.path, query: { page: page } });
},
recuperarImagem(prop) {
return "data:image/png;base64," + prop;
},
},
};
</script>
So when I navigate to page the content show fine. but when I click to go to next page "proximo" Method, the asyncData are executed (because in my back I have the log) but the page are not updated

First, remove this part:
data() {
return {};
},
And the query is directly available as follows:
async asyncData({ $api, store, query }) {
const page = parseInt(query.page);
// ...
}

Related

lag Nuxt dynamic import component

How to dynamically load components?
When opening page, they are drawn gradually/slowly
I want to draw components before rendering the page
My code:
<template>
<v-row>
<v-col
cols="12"
md="4"
v-for="element in elements" v-bind:key="element.id"
>
<component :is="element.elementName"></component>
</v-col>
</v-row>
</template>
<script>
export default {
data() {
return {
elements: null,
}
},
methods: {
getElements() {
this.$axios.post('/api/elements').then(response => {
this.elements = response.data
})
}
},
created() {
this.getElements()
},
}
</script>

Updated value not change without page refresh in Nuxt

I just started to learn Vue & Nuxt. So i have a page where i fetch all the order details and update the order state. The order state which is displayed in the UI is not getting updated asynchronously. How can i achieve reactive here ?
I need to update the value here Current Status : <b>{{ order_details.status.state }}</b> asynchronously.
Template
<template>
<v-container>
<v-row>
<v-col cols="12">
Current Status : <b>{{ order_details.status.state }}</b>
</v-col>
</v-row>
</v-container>
</template>
<template>
<v-form>
<v-container>
<v-row>
<v-col cols="12">
<div class="d-flex align-center justify-end">
<v-btn
color="primary"
class="text-subtitle-2 font-weight-medium"
#click="updateOrder"
>Update</v-btn
>
</div>
</v-col>
</v-row>
</v-container>
</v-form>
</template>
Script
export default {
async fetch({ store, params }) {
await store.dispatch("merchant/fetchOrderDetails", {
id: params.id
});
await store.dispatch("fetchMerchants");
await store.dispatch("fetchAllStatus");
},
data() {
return {
sortTypes: ["Date", "Distance"],
selectedSort: "Distance",
statusId: "",
};
},
computed: {
...mapState({
merchants: "merchants",
statusList: "statusList"
}),
...mapState("merchant", {
order_details: "orderDetails"
}),
},
methods: {
async updateOrder() {
await this.$axios
.$patch(
`/admin-portal/orders/${this.$route.params.id}`,
{
statusId: this.statusId
}
)
},
}
};
Store
export const state = () => ({
orderDetails: {}
});
export const mutations = {
SET_ORDER_DETAILS(state, orderDetails) {
state.orderDetails = orderDetails;
}
};
export const actions = {
async fetchOrderDetails({ commit }, { id }) {
const orderDetails = await this.$axios.$get(
`/pharmaceutical/admin-portal/orders/${id}`
);
commit("SET_ORDER_DETAILS", orderDetails);
}
};
You did a good chunk by yourself already. You need a few minor things to add. This is an example of code that would help you patch your thing and update vuex.
<template>
...
<v-btn #click="updateOrderInsideVuex">
Update
</v-btn>
...
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('merchant', ['updateOrder']),
async updateOrderInsideVuex() {
this.updateOrder({ paramsId: this.$route.params.id, statusId: this.statusId })
}
}
}
</script>
In your vuex store (module).
const actions = {
async updateOrder({ commit }, { paramsId, statusId }) {
const responseFromBackend = await this.$axios.$patch(`/admin-portal/orders/${paramsId}`, { statusId })
// remember to populate the vuex store with your result from the backend
// or make another call to fetch the current state of the API
commit('SET_ORDER_DETAILS_AFTER_PATCH', responseFromBackend)
},
Of course, you also need to write SET_ORDER_DETAILS_AFTER_PATCH, a typical mutation but I guess that it kinda depends of your actual data too.

NuxtJS component - component renders without data

I have a component that uses fetch to bring data via Axios and return data to render. I am using the store to set/get the data. The component renders with empty data and after debugging I see that data() method is called before fetch() method.
How to fix the problem and bring the data before the component is rendered
here is the component code:
<template>
<v-card
class="mx-auto"
max-width="500"
>
<v-sheet class="pa-4 primary lighten-2">
<v-text-field
v-model="search"
label="Search Company Directory"
dark
flat
solo-inverted
hide-details
clearable
clear-icon="mdi-close-circle-outline"
></v-text-field>
<v-checkbox
v-model="caseSensitive"
dark
hide-details
label="Case sensitive search"
></v-checkbox>
</v-sheet>
<v-card-text>
<v-treeview
:items="items"
:search="search"
:filter="filter"
:open.sync="open"
>
<template v-slot:prepend="{ item }">
<v-icon
v-if="item.children"
v-text="mdi-${item.id === 1 ? 'home-variant' : 'folder-network'}"
></v-icon>
</template>
</v-treeview>
</v-card-text>
</v-card>
</template>
<script>
export default {
async fetch(){
console.log("Hi from Fetch !!!")
let response = await this.$axios.get('/items/tasks', {baseURL: 'http://localhost:8055'});
let tasks = response.data.data;
debugger
this.$store.commit('SET_ASSIGNMENTS', tasks);
},
data () {
debugger
console.log("data assignments: ", this.$store.state.assignments);
return {
items: this.$store.state.assignments,
open: [1, 2],
search: null,
caseSensitive: false,
}
},
computed: {
filter () {
return this.caseSensitive
? (item, search, textKey) => item[textKey].indexOf(search) > -1
: undefined
},
}
}
</script>
For this I use vuex this way:
const appStore = {
state () {
return {
data: [],
}
},
getters: {
data(state) {
return state.data
},
},
mutations: {
SET_ASSIGNMENTS(state, payload) {
state.data = payload
},
},
actions: {
async getData({ commit }, {fromDate, toDate}) {
let response = await this.$axios.get('/items/tasks', {baseURL: 'http://localhost:8055'});
let tasks = response.data.data;
commit("SET_ASSIGNMENTS", tasks);
}
}
}
export default appStore
Component code is like this:
<template>
. . .
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: "MyComponent",
components: {
. . .
},
computed: {
...mapGetters({
data: 'data'
})
},
mounted(){
this.getData();
},
methods: {
getData() {
this.$store.dispatch('getData')
}
}
}
</script>
data is not reactive, you can create a computed property that returns your items
ex:reactiveItems() {return this.items}

Vue - make axios request upon parent event

I'm basically trying to figure out how to listen for an event and call the axios request and rerender the results.
I have the following parent component (A select drop down) that has a change event that calls "appSelected"
<template>
<v-app>
<v-container>
<v-select :items="results" item-text="name" item-value="id" v-model="selectedOption" #change="appSelected"
:results="results"
label="Choose Application"
dense
></v-select>
</v-container>
</v-app>
</template>
appSelected
appSelected() {
Event.$emit('selected', this.selectedOption);
}
In my child component,I have an an Axios request that I'm trying to figure out how to call and re render when choosing a different option in the drop down. I know I shouldn't use "async mounted" but not sure what to use instead.
<template>
<div id="app" v-if="appselected">
<div class="card-header">
<h5 class="card-title">Components</h5>
</div>
<v-app id="inspire">
<v-container fluid>
<v-layout row wrap>
<v-container>
<v-flex xs12 md12 class="greyBorder blue-grey lighten-5">
<div class="mr-4 ml-4 whiteback userGroupHeight">
<v-layout row wrap>
<v-flex v-for="result in results" :key="result.name" xs6>
<v-checkbox light color="success" :label="result.name" v-model="result.selected">
</v-checkbox>
</v-flex>
</v-layout>
</div>
</v-flex>
</v-container>
</v-layout>
</v-container>
</v-app>
</div>
</template>
<script>
import Vuetify from 'vuetify'
import axios from 'axios'
export default {
data () {
return {
results: [],
appselected: false
}
},
methods: {
checkLength(index) {
if (index < this.types.length - 1) {
index = index + 1;
return index;
}
},
},
async mounted() {
try {
const response = await axios.get('/componentpopulate', { params: { query: this.query, appid: 2 } })
this.results = response.data
} catch(err) {
console.log(err)
}
},
created() {
Event.$on('selected', (selectedOption) => {
this.selected = selectedOption;
this.appselected = true;
console.log('component List application id - ' + this.selected);
});
}
}
</script>
<style scoped>
.v-application {
height: 250px;
}
</style>
This is my created method is where I'm listening for the event
created() {
Event.$on('selected', (selectedOption) => {
this.selected = selectedOption;
this.appselected = true;
console.log('component List application id - ' + this.selected);
});
}
Here is where I moved to the event listener method
created() {
Event.$on('selected', (selectedOption) => {
this.selected = selectedOption;
this.appselected = true;
console.log('component List application id - ' + this.selected);
const response = axios.get('/componentpopulate', { params: { query: this.query, appid: this.selected } })
this.results = response.data
console.log(response);
});
}
Here's the answer. Add the following
.then((response) => {
this.results = response.data
console.log(response)
});
Like this
created() {
Event.$on('selected', (selectedOption) => {
this.selected = selectedOption;
this.appselected = true;
console.log('component List application id - ' + this.selected);
const response = axios.get('/componentpopulate', { params: { query: this.query, appid: this.selected } })
.then((response) => {
this.results = response.data
console.log(response)
});
});
}
Hope this helps some one.
You can try this. Use watch for your selectedOption and make your API calls in the parent component. However required parameters for API call should be in parent component with this way. Or in your store. After you can pass your results to your child component as props and display it there. Here is a small example:
Your Parent Component:
<template>
<div>
<!-- your select box -->
<Child :results="results" />
</div>
</template>
export default {
import Child from "./Child"
components: {
Child
},
data() {
return {
selectedOption : null,
results: []
}
},
watch: {
selectedOption: async function() {
await axios.get('http://jsonplaceholder.typicode.com/posts')
.then(response => {this.results = response.data})
}
}
}
And in child component:
<template>
<div>
<div v-for="item in results" :key="item.id">
{{item}}
</div>
</div>
</template>
<script>
export default {
props: ['results']
}
</script>

Error: vuex do not mutate vuex store state outside mutation handlers With uploading image

i'm kinda stuck. i get this error every time i try to update my store. what i'm doing is, i fetch my product and store it. here on upload image section (component) at created fill the image with state to show the already uploaded images, then on each upload change my state via dispatch and mutation. i know it has something to do with created() when i fill my data with state, but don't know how to solve that.
here is my template:
<v-card flat class="pb-4" max-width="450px">
<v-img class="rounded-lg theme__main__color" :src="url"></v-img>
<v-list container inline class="transparent text-center pa-0">
<v-list-item class="px-0">
<v-list-item class="px-1">
<v-btn
width="100%"
class="theme__btn__w text_main_color"
:loading="isSelecting"
#click="onChooseClick"
>{{lang.chooseimage}}</v-btn>
</v-list-item>
<v-list-item class="px-1">
<v-btn
width="100%"
class="theme__btn__s text_main_color"
#click.prevent="uploadImage"
>{{lang.upload}}</v-btn>
<input
ref="uploader"
class="d-none"
type="file"
accept="image/*"
#change="onFileChanged"
>
</v-list-item>
</v-list-item>
</v-list>
</v-card>
and this is my script:
export default {
data(){
return{
isSelecting: false,
selectedFile: null,
url: null,
placeholder: '/images/placeholder/place-800.png',
section: 'img',
pimages: [],
pId: null
}
},
methods:{
onChooseClick(){
this.isSelecting = true
window.addEventListener('focus', () => {
this.isSelecting = false
}, { once: true })
this.$refs.uploader.click()
},
onFileChanged(e) {
this.selectedFile = e.target.files[0]
this.url = URL.createObjectURL(this.selectedFile)
// do something
},
async uploadImage(){
if(this.notEmpty(this.selectedFile) && this.notEmpty(this.pId)){
const data = new FormData()
data.append('image', this.selectedFile)
data.append('pId', this.pId)
// let response = await this.axiosPost('product/createproimg', data)
this.pimages.push({"url": this.url})
this.url = this.placeholder
this.setEditProductImg(this.pimages)
}
}
},
created(){
this.url = this.placeholder
this.pId = this.editProduct.pId
this.pimages = this.editProduct.images
this.$nuxt.$on('insert',(section)=>{
if(section === 'desc' && !this.pId){
this.pId = this.editProduct.pId
}
})
}
}
and of course my store:
state:
editProduct: {
pId: null,
images: []
}
getter:
editProduct(state){
return state.editProduct
}
mutation:
SET_EDITPRODUCT_IMG(state, img){
state.editProduct.images = img
},
action:
setEditProductImg({commit}, img){
commit('SET_EDITPRODUCT_IMG', img)
},
UPDATE
thanks to #skirtle the above problem has been solved! but got a new same error on something else. as advise by #skirtle used const to mutate my state but get error. to be more clear, my state is an empty array, it will be filled the first time, but i get the error if i even try to change my select!!! let alone send another mutation!! here is the codes:
<template>
<div class="pt-6">
<v-row class="ma-0">
<v-col cols="12" md="12" class="pa-0">
<v-row class="ma-0">
<!-- form 1 -->
<template v-for="(select, index) in selects">
<component
:is="select"
:key="select.name"
v-model="catId"
#changed="addComponent(index)"
:catid="catId"
:selectindex="index"
:pcat="productCat[index]"
:subcat="subCat"
></component>
</template>
<!-- btn -->
<v-col cols="12" sm="6" md="3" class="px-1">
<v-btn width="100%" class="theme__little__color2 text_main_color px-2" #click.prevent="addCatBtn()">{{lang.addcat}}</v-btn>
</v-col>
{{selectedCatArr}}
<!-- btn -->
<addproductbtn :section="section" />
</v-row>
</v-col>
</v-row>
</div>
</template>
<script>
import addproductbtn from '~/components/global/cms/addproductbtn'
import selectcategory from '~/components/global/cms/selectcategory'
export default {
components:{
'addproductbtn': addproductbtn
},
data(){
return{
section: 'cat',
selects: [selectcategory],
catId: 0,
subCat: true,
selectedCatArr: []
}
},
methods:{
addComponent(index){
this.selects.length = index + 1
setTimeout(() => {
this.selects.push(selectcategory)
}, 1);
},
addCatBtn(){
this.goToRedirect('/cms/category/insert', this.$route.path, this.ProductId)
},
async insertCategory(){
const data = {
pId: this.editProduct.pId,
catId: this.catId
}
// let response = await this.axiosPost('product/catupdate', data)
const productCategory = this.selectedCatArr
this.setEditProductCat(productCategory)
}
},
computed:{
productCat(){
return this.editProduct.categories
},
ProductId(){
return this.editProduct.pId
}
},
created(){
this.$nuxt.$on('insert', ()=>{
this.insertCategory()
})
this.$nuxt.$on('nextcat', (subCat)=>{
this.subCat = subCat
})
this.$nuxt.$on('nextpanel', ()=>{
this.insertCategory()
})
this.$nuxt.$on('selectedcat', (selected, index)=>{
delete selected.subCategory
this.selectedCatArr.length = index
this.selectedCatArr.push(selected)
})
}
}
</script>
and my select component:
<template>
<v-col cols="12" sm="6" md="3" class="px-1 text_details_color3" v-if="showCat">
<v-select
return-object
:items="items"
:label="lang.category"
v-model="selected"
#change="emitEvent"
item-text="title"
item-value="id"
outlined></v-select>
{{selected}}
</v-col>
</template>
<script>
export default {
props:['selectindex','catid','pcat','subcat'],
data(){
return{
selected:{},
items:[],
showCat: true
}
},
async fetch(){
// this.items = await this.axiosGet(`categories/${this.catid}/1`)
this.items = [
{id: this.catid + 1, title: this.catid+'title1', subCategory: true},
{id: this.catid + 2, title: this.catid+'title2', subCategory: true},
{id: this.catid + 3, title: this.catid+'title3', subCategory: false},
{id: this.catid + 4, title: this.catid+'title4', subCategory: true}
]
},
methods:{
emitEvent(){
this.$emit('input', this.selected.id)
this.$emit('changed')
$nuxt.$emit('nextcat', this.selected.subCategory)
$nuxt.$emit('selectedcat', this.selected, this.selectindex)
}
},
computed:{
//
},
created(){
},
mounted(){
this.selected = this.pcat
this.showCat = this.subcat
}
}
</script>
I believe the problem is this line:
this.pimages.push({"url": this.url})
The array this.pimages is the same array that's inside the store state and by calling push you're modifying it outside the store.
There are a couple of ways you could fix this.
One way would be to perform the push inside a mutation, e.g. by having an ADD_EDITPRODUCT_IMG mutation:
mutation:
ADD_EDITPRODUCT_IMG(state, img){
state.editProduct.push(img)
},
You'd then call that in much the same way as with your current mutation, except that you'd just pass it the new image to add rather than passing the full array.
An alternative approach that is a bit closer to what you currently have would be to take a copy of the array rather than modifying the original:
const newImages = [...this.pimages, {"url": this.url}]
this.setEditProductImg(newImages)
Using this approach you wouldn't need any changes to your existing store.
Update:
I also suggest making pimages a computed property. There doesn't seem to be any good reason to 'copy' the data out of the store state in a created hook.