How to make pagination for Laravel resource API - laravel

I have a model that I paginate like this:
$reserve = PropertyCalendar::paginate(1);
return new ReserveResource($reserve);
I also made an API that responds with resource, and in Vue component I'll calling it with axios.get.
public function toArray($request)
{
return parent::toArray($request);
}
Here is the API response:
{
"current_page": 1,
"data": [
{
"id": 1,
"property_id": 1,
"user_id": 1,
"payable_price": 11,
"reserve_start": "2019-03-30 00:00:00",
"reserve_end": "2019-04-01 00:00:00",
"created_at":null,
"updated_at":null
}
],
"first_page_url": "http:\/\/localhost:8000\/api\/reserve?page=1",
"from": 1,
"last_page": 2,
"last_page_url": "http:\/\/localhost:8000\/api\/reserve?page=2",
"next_page_url": "http:\/\/localhost:8000\/api\/reserve?page=2",
"path": "http:\/\/localhost:8000\/api\/reserve",
"per_page": 1,
"prev_page_url": null,
"to": 1,
"total": 2
}
Now I want to know how can I make pagination for it, I can't make it with traditional Laravel pagination as it is in Vue component.
loadReserves() {
axios.get("../api/reserve", {
params: {
commentId: this.comment_id
}
}).then((response) => (this.comments = response.data.data));
},
Now I am showing data but I want to paginate it like what in the API.

If using bootstrap is not a problem for your use case, I'd recommend using this vue plugin.
I am using it myself with great results.
https://github.com/gilbitron/laravel-vue-pagination

This is some example with bootstrap showing how you can use Laravel pagination with Vue.js
Example.
<ul class="pagination">
<li class="page-item" :class="{disabled: response.current_page === 1}">
<a class="page-link" #click="previous">Previous</a>
</li>
<li
v-for="number in response.last_page"
class="page-item"
:class="{active: response.current_page === number}"
>
<a class="page-link" #click="navigateTo(number)">{{ number }}</a>
</li>
<li class="page-item" :class="{disabled: response.current_page === response.last_page}">
<a class="page-link" #click="next">Next</a>
</li>
</ul>

Related

Laravel 8 and Vue 3 with axios - paginate

I m using Laravel 8 and Vue 3 with axios. Is this https://www.npmjs.com/package/laravel-vue-pagination laravel vue pagination working with these versions of laravel and vue?
has someone used it?
THX.
here is simple pagination in vue js, this is my example form my codes
data(){
return {
current: 1,
pageSize: 4,
matchingJobs: {},
}
},
computed: {
indexStart() {
return (this.current - 1) * this.pageSize;
},
indexEnd() {
return this.indexStart + this.pageSize;
},
paginated() {
return this.matchingJobs.slice(this.indexStart, this.indexEnd);
}
},
methods: {
prev() {
this.current--;
},
next() {
this.current++;
}
getJobs(){
axios.get('/jobs').then(response => {
this.matchingjobs = response.data
}).catch(errors => {
console.log(errors)
})
},
},
created(){
this.getJobs()
}
sett current: 1 and pageSize:whatever number of items you want to be use computed to manipulate response data from your api. I am not good in explaining but I hope those codes are understandable then this should be in your html
<div v-if="matchingJobs.length">
<div class="row">
<div v-for="(job, index) in paginated" :key="index.id" class="col-xs-6 col-sm-4 col-md-3 col-lg-3 border-light mb-3">
<SingleJob :job="job" />
</div>
</div>
<!-- PAGINATION START -->
<div class="col-12 mt-4 pt-2">
<ul class="pagination justify-content-center mb-0">
<li class="page-item"><a class="page-link" #click="prev" aria-label="Previous">Prev</a></li>
<li class="page-item active"><a class="page-link" href="javascript:void(0)">{{ current }}</a></li>
<li class="page-item"><a class="page-link" #click="next()" aria-label="Next">Next</a></li>
</ul>
</div><!--end col-->
<!-- PAGINATION END -->
I hope this will be helpful

Laravel-Vue-Pagination error when trying to go to a different page

api.php
Route::get('/products', 'ProductsController#index');
Query:
$products = DB::table('sizes')
->join('products', 'sizes.id', '=', 'products.sizes')
->join('categories', 'products.category', '=', 'categories.id')
->select('products.*', 'categories.catname', 'categories.catimage', 'categories.catdescription', 'sizes.size')
->where([['products.is_active', '=', 1],['categories.is_active', '=', 1],])
->orderBy('products.id', 'ASC')
->paginate(5);
return $products;
Vue component:
<div v-for="product in products.data" :key="product.id">
<h1>{{ product.name }}</h1>
</div>
<pagination :data="products" #pagination-change-page="getResults"></pagination>
methods: {
getResults(page = 1) {
this.$url.get('products/results?page=' + page)
.then(response => {
console.log(response)
this.products = response.data;
});
}
}
The initial load of products works, it shows 5 products and shows pagination. Whenever I try to click a new page from the pagination, I end up with multiple errors.
CORS(which I don't see how since my app is completely public) and two network errors
from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
net::ERR_FAILED
Uncaught (in promise) Error: Network Error
Is there something I'm missing here? Am I supposed to make another endpoint that handles pagination or should this be handled from the same exact endpoint where it fetches initial pagination?
1. Copy and paste this code in a new component, like 'Pagination.vue'
<template>
<nav aria-label="...">
<ul class="pagination justify-content-center">
<li class="page-item" :class="{ disabled: pagination.current_page <= 1 }">
<a style="cursor:pointer" class="page-link" #click.prevent="changePage(1)" >First page</a>
</li>
<li class="page-item" :class="{ disabled: pagination.current_page <= 1 }">
<a style="cursor:pointer" class="page-link" #click.prevent="changePage(pagination.current_page - 1)"><i class="fa fa-arrow-left"></i></a>
</li>
<li class="page-item" v-for="(page,index) in pages" :key="page" :class="isCurrentPage(page) ? 'active' : ''">
<a style="cursor:pointer" class="page-link" #click.prevent="changePage(page)">{{ page }}
<span v-if="isCurrentPage(page)" class="sr-only">(current)</span>
</a>
</li>
<li class="page-item" :class="{ disabled: pagination.current_page >= pagination.last_page }">
<a style="cursor:pointer" class="page-link" #click.prevent="changePage(pagination.current_page + 1)"><i class="fa fa-arrow-right"></i></a>
</li>
<li class="page-item" :class="{ disabled: pagination.current_page >= pagination.last_page }">
<a style="cursor:pointer" class="page-link" #click.prevent="changePage(pagination.last_page)">Last Page</a>
</li>
</ul>
</nav>
</template>
<script>
export default {
props:['pagination', 'offset'],
methods: {
isCurrentPage(page){
return this.pagination.current_page === page
},
changePage(page) {
if (page > this.pagination.last_page) {
page = this.pagination.last_page;
}
this.pagination.current_page = page;
this.$emit('paginate');
}
},
computed: {
pages() {
let pages = []
let from = this.pagination.current_page - Math.floor(this.offset / 2)
if (from < 1) {
from = 1
}
let to = from + this.offset -1
if (to > this.pagination.last_page) {
to = this.pagination.last_page
}
while (from <= to) {
pages.push(from)
from++
}
return pages
}
}
}
</script>
2. Make it global in your js/app.js file,
Vue.component('pagination', require('./components/Pagination.vue').default);
3. In the vue component, below to the data, set the pagination component like this, you can cange the offset as much you can
<pagination v-if="pagination.last_page > 1"
:pagination="pagination"
:offset="7"
#paginate="getItems()">
</pagination>
4. Set current page to 1,
data(){
return{
items: [],
pagination: {
current_page: 1,
},
}
},
5. Make a method to send the page number and collect paginated data,
getItems(){
axios.get('api/items?page='+this.pagination.current_page)
.then(response => {
this.items = response.data.data;
this.pagination = response.data.meta;
});
},
6. Make sure you return data paginated data with resource collection,
public function index(){
return new GeneralCollection(Item::with('category')->orderBy('name')->paginate(10));
}
***if you, don't have the collection file, make one , like 'GeneralCollection',
php artisan make:resource GeneralCollection
then, include it on the controllers where you want to return collected data,
use App\Http\Resources\GeneralCollection;
7. Congrats !

Laravel bind data on vue tamplate

I am trying to bind user_name to Vue from this Laravel Object:
{ "order": [ { "id": 87, "user_id": "2", "user_name": "Mohamed Hassan", "table": 20, "total": 224, "status": 1, "delivered": 0, "paied": 0, "created_at": "2019-09-14 15:04:40", "updated_at": "2019-09-14 15:04:40" } ] }
and this object get from:
{{order.data}}
I also tried with this:
{{order.data['order']['user_name']}}
but it returns null
and this is my Vue template
<li v-for="order in orders">
<div class="col-md-3 col-sm-3 col-xs-3"><div class="notify-img">{{order.data}}</div></div>
<div class="col-md-9 col-sm-9 col-xs-9 pd-l0">
Date:
{{order.created_at}}
<i class="fa fa-dot-circle-o"></i>
<p>Lorem ipsum sit dolor amet consilium.</p>
<p class="time">1 Saat önce</p>
<hr>
</div>
</li>
If I see it properly, then the order is actually an array holding a single object.
You could try:
{{ order.data['order'][0]['user_name'] }}

VueJS: v-for directive is not rendering items in spite of having objects in array

I am trying to render my API response object into the table rows. There is no problem with endpoints. I could fetch data without any issues. Data is paginated. I can see the content of the array object(by using double curly braces). But v-for direction doesn't affect anything.
I tried some ways to fix. One of them is using response.data.data to handle it but it didn't work. I also tried iterating through customers.data but I got the same results.
This part was taken from my component
import axios from 'axios'
export default {
data () {
return {
customers: [],
}
},
mounted: function() {
axios.get('http://127.0.0.1:8000/customer/all').then(res => {
this.customers.push(res.data);
});
},
Here it is the directive part:
<tr v-for="customer in customers">
<td>
<input class="uk-checkbox" type="checkbox">
</td>
<td>{{ customer.mail }}</td>
<td>
{{ customer.telephone }}
</td>
<td>
<ul class="uk-iconnav">
<li><span class="uk-icon" uk-icon="icon: check"></span></li>
<li><span class="uk-icon" uk-toggle="target: #user-request" uk-icon="icon: question"></span></li>
<li><span class="uk-icon" uk-icon="icon: trash"></span></li>
</ul>
</td>
</tr>
{{ customers }} => this is OK
customers json output
[ { "current_page": 1, "data": [ { "id": 1, "user_info": "test", "password": "test", "gsm": "123123213", "telephone": 124, "mail": "test#test", "address": "test", "created_at": null, "updated_at": null } ], "from": 1, "last_page": 1, "next_page_url": null, "path": "http://127.0.0.1:8000/customer/all", "per_page": 4, "prev_page_url": null, "to": 1, "total": 1 } ]
It should be rendered, but it's not rendering. I didn't get any console errors. What is the problem? Thanks anyway.
In your snippet, res.data is an array that contains an object with a data attribute that has for value the customer data you want to display.
To store the retrieved customer data values in your component's customers array you can spread them as the following :
mounted: function() {
axios.get('http://127.0.0.1:8000/customer/all').then(res => {
this.customers.push(...res.data[0].data);
});
}
If the customers array as no other modification source, you can even do :
mounted: function() {
axios.get('http://127.0.0.1:8000/customer/all').then(res => {
this.customers = res.data[0].data;
});
}

Pagination Laravel AJAX?

By default Laravel pagination refresh page every time. I don't want this to happen
public function getPaginate($n)
{
return $this->model->with('professional')
->orderBy('extras.created_at', 'desc')
->paginate($n);
}
In the controller :
$extras = $this->extraRepository->getPaginate(3);
$links = $extras->render();
And i send $link to the view.
<div class="pagination">{!! $links !!}</div>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<ul class="large-block-grid-3 medium-block-grid-2 small-block-grid-1">
#if(empty($extras))
<p class="empty-notice">Sorry, no extra available at the moment. Come back later</p>
#else
#foreach ($extras as $extra)
<li class="extra-available">#include('user.card', ["description" => $extra->professional->company_name." in ".
$extra->type.
' for '.$extra->date.' at '.$extra->date_time,
"title" => $extra->professional->company_name,
"image" => asset("../resources/assets/images/extra-card-example.png"),
"id" => $extra->id])
</li>
#endforeach
#endif
</ul>
</div>
</div>
I tried to implement an AJAX request like so :
$(".pagination a").click(function(e){
e.preventDefault();
var url = $(this).attr('href');
//alert(url);
$.ajax({
url: url,
type: "GET",
success: function(data){
$('.extra-available').html(data);
}
});
});
but it returns me an entire html doc, i just want what's in .extra-available.
Any ideas ?
I think it is better to prepare API to be called by your ajax in json format. The json return is very useful to do paginate. You will get as below data (in laravel 5.2).
{
"total": 18,
"per_page": 15,
"current_page": 1,
"last_page": 2,
"next_page_url": "http://example.com/products?page=2",
"prev_page_url": null,
"from": 1,
"to": 15,
"data": [] // a list of your data here
}
You API controller will be look like this. Dont need to use the $n. Laravel will get the current page from the page GET parameter
$data = Model::orderBy('extras.created_at', 'desc')->paginate();
return response()->json($data);
So your ajax code can call the next page data based in the next_page_url, as well as the previous page using prev_page_url if it exist. All about paging is there including total records, current page and total records display in page
Try this:
$(document).on('click', '.pagination a', function (e) { ...

Resources