How have you come to have this response; what Paginator are you using?
paginating from my response
hi, so I have a data response as follows::
data: {offset: 0, limit: 20, total: 1559, count: 20, results....
How can I use this to paginate to the next and previous page?
Thanks
You can use a length aware paginator, just suggestion. It's covered in the laravel API.
so I don't have access to the backend. I just have the results in the api response
What should a URL for the next page look like; is there a page query parameter, or do you provide an offset and count???
I do have the option to pass limit and offset in:
?limit=100&offset=10
You can make next prev links using the provided query string.
Edit: sometimes you have to keep track of the current page or offset using a hidden field. Or however you need. Just make the links.
How?
They are just a href links.
I am on mobile, I will boot my desktop.
@boyjarv see this video: https://laracasts.com/series/javascript-techniques-for-server-side-developers/episodes/1 Server fetched partials and adapt to your case.
Basically a next
$("#nextp").click(function (event)
{
var variable = $('#counter').html();
var newvar = parseInt(variable) + 1;
var maxpage = parseInt($('#mp').html());
if (newvar > maxpage) {
newvar = maxpage;
}
$('#counter').text(newvar);
var url = '<?php echo DIR . "account/index?page="; ?>' + newvar;
var element = document.getElementById('div1');
fload(url, element);
});
<a href="javascript:void(0);" id="nextp">next</a> // a link
And the fetch:
function fload(url, element)
{
fetch(url)
.then(function (response) {
return response.text();
})
.then(function (body) {
element.innerHTML = body;
});
}
I use a partial page load, but you should be able to adapt the video and example to your use case. I use some hidden fields to track max page and current page, in example I just used counter.
Example and suggestions only. Also a suggestion, take more lessons, many free javascript lessons on laracasts.
You could make a class to interact with the response data:
class Paginator {
constructor (response) {
this.response = response;
this.path = window.location.pathname;
this.query = new URLSearchParams(window.location.search);
}
nextPage () {
let offset = this.response.offset + this.response.limit;
this.query.set('offset', (offset < this.response.total) ? offset : this.response.offset);
return `${this.path}?${this.query}`;
}
prevPage() {
// similar implementation
}
}
let p = new Paginator(response);
// p.nextPage()
You will basically pass the response into the Paginator class, and nextPage, prevPage urls - you could go further if you need more from your Paginator
hmm, shouldn't pagination be really easy these days?
There may be something on NPM 🤷♂️ - generally a well-designed API response will include previous and next links
You need to learn how to write a paginator, it is easy to write one. Just suggestion.
But for one in custom javascript, the one in laravel won't work, I just create custom links.
Thank you all for your help!
It is really not difficult to implement something like this yourself.
You are welcome.
Here is the data that is returned in from the api call, just a bit stuck on how to implement this:
"data": {
"offset": 0,
"limit": 20,
"total": 30920,
"count": 20,
"results": [{array of objects}}]
}
Like I mentioned previously, you can make a class to handle this data; share your Vue component script and I'll show you.
Vue component script:
import { mapState } from 'vuex'
export default {
name: 'Character',
data() {
return {
charImageUrl: '',
charImageSize: 'detail.jpg',
charStores: [],
charSeries: [],
charEvents: [],
personalData: {
name: 'BONZO',
imgUrl: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTn9gW4RiQbFYtV8YUcZGd-iocJ98Nq9oZ38A&usqp=CAU'
}
}
},
computed: {
...mapState({
character: state => state.character,
preUrl: state => state.charImageUrl,
stories: state => state.charStories,
series: state => state.charSeries,
events: state => state.charEvents,
pd: state => state.personalData
})
},
mounted() {
console.log('pd:', this.pd)
this.$store.dispatch('getCharacter', this.$route.params.id, this.personalData)
this.getImage()
this.setPersonalData()
},
methods: {
getImage() {
this.charImageUrl = `${this.preUrl}/${this.charImageSize}`
},
setPersonalData() {
this.$store.commit("setPersonal", this.personalData)
}
}
}
VUX:
import { createStore } from 'vuex'
import axios from 'axios'
import { public_key } from '../marvel'
export default createStore({
state: {
characters: [],
character: [],
charImageUrl: '',
charStories: [],
charSeries: [],
charEvents: [],
personalData: {
name: '',
imageUrl: ''
}
},
mutations: {
getCharacters(state) {
state.characters = []
axios.get(`http://gateway.marvel.com/v1/public/characters?apikey=${public_key}`)
.then((res) => {
console.log('res: ', res)
res.data.data.results.forEach((item) => {
state.characters.push(item)
})
})
.catch((err) => {
console.log(err)
})
},
getCharacter(state, id){
state.character = []
state.charStories = []
state.charSeries = []
state.charEvents = []
axios.get(`http://gateway.marvel.com/v1/public/characters/${id}?apikey=${public_key}`)
.then(res => {
res.data.data.results.forEach((item) => {
state.character.push(item)
state.charImageUrl = `${item.thumbnail.path}/`
item.stories.items.forEach((story) => {
state.charStories.push(story)
})
item.series.items.forEach((programme) => {
state.charSeries.push(programme)
})
item.events.items.forEach((event) => {
state.charEvents.push(event)
})
})
})
.catch((err) => {
console.log(err)
})
},
setPersonal (state, personalData) {
state.personalData = personalData
}
},
actions: {
getCharacters: context => {
context.commit('getCharacters')
},
getCharacter(context, id) {
context.commit('getCharacter', id)
}
},
modules: {
}
})
Where's the query with offset and limit query params???
I would add it into here:
axios.get(`http://gateway.marvel.com/v1/public/characters?apikey=${public_key}`)
// resources/js/Paginator.js
export default class Paginator {
constructor(response, url = null) {
this.response = response;
this.url = new URL(url || window.location.href)
}
items () {
return this.response.results;
}
hasMore () {
return this.response.offset + this.response.limit < this.response.
}
nextPageUrl() {
this.url.searchParams.set('offset', this.hasMore() ? this.response.offset + this.response.limit : this.response.offset);
this.url.searchParams.set('limit', this.response.limit);
return this.url.toString();
}
prevPageUrl() {
this.url.searchParams.set('offset', Math.max(0, this.response.offset - this.response.limit));
this.url.searchParams.set('limit', this.response.limit);
return this.url.toString();
}
}
Then pass the response of the successful axios request into a new Paginator instance, along with the URL so we can build the prev and next URLs
const Paginator = require('@/Paginator.js');
//...
getCharacters(state) {
state.characters = []
let url = `http://gateway.marvel.com/v1/public/characters?apikey=${public_key}`
axios.get(url)
.then((res) => {
let characters = new Paginator(res, url);
state.characters.concat(...characters.items());
// you can get the prevPage and nextPage URLs from the Paginator
// depending on how you intend to use them, you could decide to
// put this data in `state` along with the original URL above.
})
I should also say; hitting a third party API directly from your frontend is possibly not the best idea. Your API key is exposed; and you would probably burn through the hourly/daily limits quickly. In these situations, I would handle queries to the third party API in my Laravel app, exposing an internal endpoint which provides data to the Vue application. In this scenario, you are hiding your API key from malicious users, and you have the opportunity to cache the API responses, therefore giving you control over how often it hit.
Thank you for this Tykus, it's a bit much for what I need to do...
I am now getting: TypeError: Paginator is not a constructor at eval (index.js?4360:26)
Please or to participate in this conversation.