Website pagination with query string in vuejs - javascript

In home page i have container where i am showing some elements, and below there is a pagination with all the pages(1, 2, 3, 4...), pagination is working. But, i want to add a query in my url so if type something like http://localhost:8080/twity/?page=10 i want to go to that page. I am adding a query like this, but it is only showing a number of the current page i am at, if i change number in url it is just returning me back to the first(default) page...
this.$router.push({ query: { page: this.currentPage } })
I can share my whole Home component code if needed. Thanks.
Home component
<template>
<div class="main">
<div class="tweets-container">
<div
v-for="tweet in tweets"
:key="tweet.id"
>
<div class="tweet-card">
<div class="username-time">
<div class="user-info">
<p class="name">
{{ tweet.twitter_name }}
</p>
<p class="user-info-p">
#
</p>
<p class="username">
<a
:href="'https://twitter.com/' + tweet.twitter_username"
class="twitter_link"
target="_blank"
>
{{ tweet.twitter_username }}
</a>
</p>
</div>
<div class="time">
<p>{{ tweet.added_at }}</p>
</div>
</div>
<div class="text">
<p>{{ tweet.tweet_text }}</p>
</div>
</div>
</div>
</div>
<div class="reply-container">
<h1>Replies</h1>
</div>
<ul class="pagination">
<li class="page-item">
<p
class="hover-underline-animation"
#click="previousPage"
>
Previous
</p>
</li>
<li class="page-item all-pages">
<div
v-for="page in numberOfPages"
:key="page"
:class="page == currentPage ? 'active' : 'hover-underline-animation'"
#click="getTweets(page)"
>
<p>{{ page }}</p>
</div>
</li>
<li class="page-item">
<p
class="hover-underline-animation"
#click="nextPage"
>
Next
</p>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
import { getUserToken } from '#/auth/auth'
import moment from 'moment'
export default {
components: {},
data() {
return {
tweets: [],
currentPage: 1,
numberOfPages: 0,
}
},
beforeMount() {
this.getTweets()
},
methods: {
nextPage() {
this.currentPage += 1
this.tweets = []
this.getTweets()
},
previousPage() {
this.currentPage -= 1
this.tweets = []
this.getTweets()
},
getTweets(newCurrent) {
this.tweets = []
const API_URL = `${this.$server}/api/twitter/tweets`
const params = {
token: getUserToken(),
page: this.currentPage,
newCurrentPage: newCurrent,
}
axios.post(API_URL, null, { params }).then(res => {
this.currentPage = res.data.page
this.numberOfPages = res.data.numberOfPages
// Set query string
this.$router.push({ query: { page: this.currentPage } })
res.data.tweets.forEach(tweet => {
const tweetData = {
id: tweet.id,
tweet_text: tweet.tweet_text,
twitter_name: tweet.twitter_name,
twitter_username: tweet.twitter_username,
added_at: moment(String(tweet.added_at)).format('MM/DD/YYYY hh:mm'),
}
this.tweets.push(tweetData)
})
})
},
},
}
</script>
Nodejs function(this is for getting data from db and controlling pagination)
getAllTweets: async (req) => {
// get number of all rows in table
let tweetsNum = await SQL('SELECT COUNT(*) as total FROM twitter_tweets')
tweetsNum = tweetsNum[0].total
// number of tweets
const pageSize = 25
let skip = 0
const numberOfPages = Math.ceil(tweetsNum / pageSize)
// page number from client
const newCurrentPage = req.query.newCurrentPage
let currentPage = req.query.page
// check if there is newCurrentPage
if(newCurrentPage != undefined) {
skip = (newCurrentPage - 1) * pageSize
currentPage = newCurrentPage
} else {
// check if page is valid)
if(currentPage < 1) {
currentPage = 1
} else if(currentPage > numberOfPages) {
currentPage = numberOfPages
}
// offset
skip = (currentPage - 1) * pageSize
}
// paginate tweets from db
const tweetsFromDb = await SQL('SELECT * FROM twitter_tweets ORDER BY added_at DESC LIMIT ?,?', [skip, pageSize])
let tweets = Object.values(JSON.parse(JSON.stringify(tweetsFromDb)))
const data = {
tweets: tweets,
page: parseInt(currentPage),
numberOfPages: parseInt(numberOfPages),
}
return data
}

beforeRouteUpdate(to,from,next) {
yourFunctionXXXXX(to.query);
next();
},
beforeRouteEnter(to, from, next) {
next((vm) => {
vm.yourFunctionXXXXX(to.query);
});
},
You should first use the route pre-guard to intercept your route parameters, and then manually decide what content you should display based on the parameters

Related

Toggle class(or change style) of element when element in clicked, Vuejs

The way i am getting data is little bit complicated. I have "tweets" array where data is stored and each tweet is a card where i successfully change style when card is clicked(markTweet function), but there are also replies for each tweet which are shown same as tweets(each reply has its own card). The way i am getting data from server:
let replies = []
for(const tweet of tweets) {
let reply = await SQL('SELECT * FROM tweet_replies WHERE tweet_replies.conversation_id = ?', tweet.tweet_id)
replies.push(reply)
}
const data = {
tweets: tweets,
page: parseInt(currentPage),
numberOfPages: arr,
replies
}
Then i have component in vue. You can see replies are stored in tweets array in each tweet as tweetReplies.
In markReply func, am succesfully adding id to array.
<template>
<div class="container-full">
<div class="tweets-container">
<div
v-for="(tweet, i) in tweets"
:key="tweet.id"
>
<div
class="tweet-card"
:class="{ selected: tweet.isSelected }"
#click="markTweet(tweet.tweet_id, i)"
>
<div class="text">
<p
v-html="tweet.tweet_text"
>
{{ tweet.tweet_text }}
</p>
</div>
</div>
<div class="replies">
<div
v-for="(reply, index) in tweet.tweetReplies"
:key="reply.tweet_id"
#click="markReply(reply.tweet_id, index)"
>
<div class="tweet-card tweet-reply">
<div class="text">
<p>
{{ reply.tweet_text }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { getUserToken } from '#/auth/auth'
import moment from 'moment'
import { BFormTextarea, BButton, BFormSelect } from 'bootstrap-vue'
export default {
components: { BFormTextarea, BButton, BFormSelect },
data() {
return {
tweets: [],
tweetActionIds: [],
categories: [],
}
},
beforeMount() {
this.getTweets()
},
methods: {
getTweets() {
this.tweets = []
const API_URL = `${this.$server}/api/twitter/tweets`
const params = {
token: getUserToken(),
page: this.$route.query.page,
newCurrentPage: newCurrent,
}
axios.post(API_URL, null, { params }).then(res => {
this.currentPage = res.data.page
this.numberOfPages = res.data.numberOfPages
if (res.data) {
res.data.tweets.forEach(tweet => {
const tweetData = {
id: tweet.id,
tweet_id: tweet.tweet_id,
tweet_text: htmlText,
tweet_text_en: htmlTextEn,
twitter_name: tweet.twitter_name,
twitter_username: tweet.twitter_username,
added_at: moment(String(tweet.added_at)).format(
'MM/DD/YYYY hh:mm',
),
URL: tweet.URL,
isSelected: false,
tweetReplies: [],
}
this.tweets.push(tweetData)
})
res.data.replies.forEach(reply => {
reply.forEach(r => {
this.tweets.forEach(tweet => {
if (tweet.tweet_id === r.conversation_id) {
tweet.tweetReplies.push(r)
}
})
})
})
}
})
},
markTweet(tweetId, i) {
const idIndex = this.tweetActionIds.indexOf(tweetId)
this.tweets[i].isSelected = !this.tweets[i].isSelected
if (this.tweetActionIds.includes(tweetId)) {
this.tweetActionIds.splice(idIndex, 1)
} else {
this.tweetActionIds.push(tweetId)
}
},
markReply(replyId) {
const idIndex = this.tweetActionIds.indexOf(replyId)
if (this.tweetActionIds.includes(replyId)) {
this.tweetActionIds.splice(idIndex, 1)
} else {
this.tweetActionIds.push(replyId)
}
},
},
}
</script>
I have tried to add replySelected in data and then when click is triggered in markReply i changed replySelected to true, but every reply of a tweet was then selected, which is not what i want.
If I understood you correctly try like following snippet:
const app = Vue.createApp({
data() {
return {
tweets: [{id: 1, tweet_id: 1, isSelected: true, tweet_text: 'aaa', tweetReplies: [{tweet_id: 11, tweet_text: 'bbb'}, {tweet_id: 12, tweet_text: 'ccc'}]}, {id: 2, tweet_id: 2, isSelected: false, tweet_text: 'ddd', tweetReplies: [{tweet_id: 21, tweet_text: 'eee'}, {tweet_id: 22, tweet_text: 'fff'}]}],
tweetActionIds: [],
}
},
methods: {
markTweet(tweetId, i) {
const idIndex = this.tweetActionIds.indexOf(tweetId)
this.tweets[i].isSelected = !this.tweets[i].isSelected
if (this.tweetActionIds.includes(tweetId)) {
this.tweetActionIds.splice(idIndex, 1)
} else {
this.tweetActionIds.push(tweetId)
}
},
markReply(replyId) {
const idIndex = this.tweetActionIds.indexOf(replyId)
if (this.tweetActionIds.includes(replyId)) {
this.tweetActionIds.splice(idIndex, 1)
} else {
this.tweetActionIds.push(replyId)
}
},
checkReply(r) {
return this.tweetActionIds.includes(r) ? true : false
}
},
})
app.mount('#demo')
.selected {color: red;}
<script src="https://cdn.jsdelivr.net/npm/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<div class="container-full">
<div class="tweets-container">
<div v-for="(tweet, i) in tweets" :key="tweet.id">
<div
class="tweet-card"
:class="{ selected: tweet.isSelected }"
#click="markTweet(tweet.tweet_id, i)"
>
<div class="text">
<p v-html="tweet.tweet_text">
{{ tweet.tweet_text }}
</p>
</div>
</div>
<div class="replies">
<div
v-for="(reply, index) in tweet.tweetReplies"
:key="reply.tweet_id"
#click="markReply(reply.tweet_id, index)"
>
<div class="tweet-card tweet-reply">
<div class="text" :class="{selected: checkReply(reply.tweet_id)}">
<p>{{ reply.tweet_text }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{tweetActionIds}}
</div>
You can build on Nikola's answer by bypassing the extra step of adding isSelected to each individual Tweet by just checking if it's in the tweetActionIds array, and then do the same with the replies to keep it clean
<div id="demo">
<div class="container-full">
<div class="tweets-container">
<div
v-for="(tweet, i) in tweets"
:key="tweet.id"
>
<div
class="tweet-card"
:class="{ selected: isActive(tweet) }"
#click="markTweet(tweet.tweet_id, i)"
>
<div class="text">
<p v-html="tweet.tweet_text">
{{ tweet.tweet_text }}
</p>
</div>
</div>
<div class="replies">
<div
v-for="(reply, index) in tweet.tweetReplies"
:key="reply.tweet_id"
#click="markReply(reply.tweet_id, index)"
>
<div
:class="{ selected: isActive(reply) }"
class="tweet-card tweet-reply"
>
<div class="text">
<p>{{ reply.tweet_text }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{tweetActionIds}}
</div>
const app = Vue.createApp({
data() {
return {
tweets: []
tweetActionIds: [],
categories: [],
}
},
methods: {
markTweet(tweetId, i) {
const idIndex = this.tweetActionIds.indexOf(tweetId)
if (this.tweetActionIds.includes(tweetId)) {
this.tweetActionIds.splice(idIndex, 1)
} else {
this.tweetActionIds.push(tweetId)
}
},
markReply(replyId) {
const idIndex = this.tweetActionIds.indexOf(replyId)
if (this.tweetActionIds.includes(replyId)) {
this.tweetActionIds.splice(idIndex, 1)
} else {
this.tweetActionIds.push(replyId)
}
},
isSelected(tweet) {
return this.tweetActionIds.includes(tweet.tweet_id);
}
},
})

What is a good way to call a function that makes an axios request using information from within a v-for?

I am working on an e-commerce site using rails and VueJS. I have a component file to display the orders of a given user. I am using a v-for loop to iterate and display all the user's order info. each order is linked to a carted products table where the product I.D. is located. I want to display the product information of each product within each order. I have a productShow function that makes an axios request to the backend and retrieves the product's info, the problem is I'm not sure how to capture the product ID from each of the products in the carted product array to send with the request. Even if I manage that how would I display each product within each order and the order's info as well? I have been unsuccessful in my attempts thus far and am looking for some guidance. code and info below.
ordersIndex.Vue component:
<div class="home">
<h1>{{ message }}</h1>
<div v-for="order in orders">
<h2>Order Number:{{ order.id }}</h2>
<h1 v-for="cartedProduct in order.carted_products"> <strong>{{ cartedProduct }}</strong> </h1>
<h3>SUBTOTAL:{{ order.subtotal }}</h3>
<h3>TAX:{{ order.tax }}</h3>
<h3>TOTAL: {{ order.total }}</h3>
</div>
</div>
</template>
<style>
</style>
<script>
import axios from "axios";
export default {
data: function () {
return {
message: "Your Orders",
orders: [],
anOrder: [],
cartedProducts: [],
product: {},
productId: "",
};
},
created: function () {
console.log("In Created...");
this.orderIndex();
// this.cartedProductsonOrder();
},
methods: {
orderIndex: function () {
console.log("In orderIndex...");
axios.get("/api/orders").then((response) => {
console.log(response.data);
this.orders = response.data;
this.cartedProductsonOrder();
});
},
productShow: function (id) {
console.log("in products show");
axios.get("/api/products/" + id).then((response) => {
console.log(response.data);
this.product = response.data;
console.log("Line 53");
console.log(this.product);
this.cartedProducts.push(this.product);
console.log(this.cartedProducts);
});
},
cartedProductsonOrder: function () {
console.log("In cartedProductsonOrder method....");
console.log(this.orders);
for (let i = 0; i < this.orders.length; i++) {
console.log("Line 62");
console.log(this.orders[i].carted_products);
this.cartedProducts = this.orders[i].carted_products;
for (let j = 0; j < this.cartedProducts.length; j++) {
console.log("Line 67");
console.log(this.cartedProducts[j]);
console.log(this.cartedProducts[j].product_id);
this.productId = this.cartedProducts[j].product_id;
this.productShow(this.productId);
}
}
},
},
};
</script>
Screenshots of console log:
order response
carted products
This is completely untested however, it should give you a good idea of how to accomplish what you're after. I have also made a few other changes such as using fat arrow functions and changing to forEach loops instead of basic for loops.
<template>
<div class="home">
<h1>{{ message }}</h1>
<div v-for="order in orders">
<h2>Order Number:{{ order.id }}</h2>
<h1 v-for="product in order.carted_products"> <strong>{{ cartedProduct }}</strong> </h1>
<h3>SUBTOTAL:{{ order.subtotal }}</h3>
<h3>TAX:{{ order.tax }}</h3>
<h3>TOTAL: {{ order.total }}</h3>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data: () => ({
message: "Your Orders",
orders: [],
cartedProducts: []
}),
mounted: {
this.doGetOrders()
},
methods: {
doGetOrders: () => {
axios.get(`/api/order`).then((response) => {
this.orders = response.data
this.doCartedProductsInOrder()
})
},
doCartedProductsInOrder: () => {
if (this.order.length >= 1) {
this.order.forEach((order) => {
if (order.cartedProducts >= 1) {
order.cartedProducts.forEach((product) => {
this.cartedProducts.push(this.doGetProductInfo(productId))
})
}
})
}
},
doGetProductInfo: (productId) => {
axios.get(`/api/products/${productId}`).then((response) => {
if (response.status === 200) {
return response.data
}
})
}
}
}
</script>

Pagination in vue visible items

I build a pagination component that works fine. But I don't know how to limit the shown items in the v-for loop and show the next items on the next page.
this is the pagination component:
<template>
<div>
<ul class="pagination">
<li class="pagination-item">
<button
type="button"
#click="onClickFirstPage"
:disabled="isInFirstPage"
>
First
</button>
</li>
<li class="pagination-item">
<button
type="button"
#click="onClickPreviousPage"
:disabled="isInFirstPage"
>
Previous
</button>
</li>
<li v-for="page in pages" :key="page.name" class="pagination-item">
<button #click="onClickPage(page.name)" type="button" :disabled="page.isDisabled" :class="{ active: isPageActive(page.name )}">
{{ page.name }}
</button>
</li>
<!-- Range of pages -->
<li>
<button
type="button"
#click="onClickNextPage"
:disabled="isInLastPage"
>
Next
</button>
</li>
<li>
<button
type="button"
#click="onClickLastPage"
:disabled="isInLastPage"
>
Last
</button>
</li>
</ul>
</div>
<script>
export default {
props: {
maxVisibleButtons: {
type: Number,
required: false,
default: 3
},
totalPages: {
type: Number,
required: true
},
total: {
type: Number,
required: true
},
currentPage: {
type: Number,
required: true
}
},
computed: {
startPage() {
// When on the first page
if(this.currentPage === 1) {
return 1;
}
// When on the last page
if(this.currentPage === this.totalPages) {
return this.totalPages - this.maxVisibleButtons;
}
// When in between
return this.currentPage - 1;
},
pages() {
const range = [];
for(let i = this.startPage; i <= Math.min(this.startPage + this.maxVisibleButtons - 1, this.totalPages); i+=1) {
range.push({
name: i,
isDisabled: i === this.currentPage
});
}
return range;
},
isInFirstPage() {
return this.currentPage === 1;
},
isInLastPage() {
return this.currentPage === this.totalPages;
},
},
methods: {
onClickFirstPage() {
this.$emit("pagechanged", 1);
},
onClickPreviousPage() {
this.$emit("pagechanged", this.currentPage - 1);
},
onClickPage(page) {
this.$emit('pagechanged', page);
},
onClickNextPage() {
this.$emit('pagechanged', this.currentPage + 1);
},
onClickLastPage() {
this.$emit('pagechanged', this.totalPages);
},
isPageActive(page) {
return this.currentPage === page;
}
}
}
</script>
<style scoped lang="scss">
.pagination {
list-style-type: none;
}
.pagination-item {
display: inline-block;
}
.active {
background-color: #4AAE9B;
color: #ffffff;
}
</style>
my v-for with the items
<div
v-for="casino in orderBy(filteredCasinos, 'Rating', -1)"
:key="casino.id + '-filterd'"
class="casino-card"
v-show="filteredCasinos.length > 1"
>
At the moment the pagination works when I click to the next page but as I mentioned all items get shown and I want to limit them.
Use a computed property to keep track what should be visible on the current page.
With a computed property you can easily introduce a filter on the items. Then just create the functions that sets the current page, and BAM - a paginated view of items.
The snippet below does all this, and also gives the ability to choose how many items should be visible on a given page.
Advice:
new Vue({
el: "#app",
data() {
return {
posts: [],
currentPage: 1,
postsPerPage: 10,
}
},
computed: {
// computed property to set the items visible on current page
currentPagePosts() {
return this.posts.slice((this.currentPage - 1) * this.postsPerPage, this.currentPage * this.postsPerPage)
}
},
methods: {
// pagination function
setCurrentPage(direction) {
if (direction === -1 && this.currentPage > 1) {
this.currentPage -= 1
} else if (direction === 1 && this.currentPage < this.posts.length / this.postsPerPage) {
this.currentPage += 1
}
}
},
// fetching example data (200 post-like items)
async mounted() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos')
this.posts = await response.json()
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="setCurrentPage(-1)">PREV</button>
<button #click="setCurrentPage(1)">NEXT</button><br /> Current page / max page: {{ currentPage }} / {{ Math.ceil(posts.length / postsPerPage) }}<br />
<label>Set posts per page: <input v-model="postsPerPage" type="text" /></label>
<hr />
<!-- the v-for only lists items from the computed property -->
<div v-for="post in currentPagePosts" :key="post.id">
ID: {{ post.id }} Title: {{ post.title }}
</div>
</div>

Vue.js: Vue-Carousel jumping to last item in array on click

I am currently working on an application that involves scrolling through members from two different lists. Once you click one you see their image and bio. We added up and down arrows to scroll through their biography, but when i click the down arrow it seems that the active class on the carousel slide now jumps to the last member in my array, but still displays the member i was already on. To add to that I cannot swipe back and forth once i am on a member (this is something that I could do previously.) I know this probably isn't the best description and there is only so much code I can show, as I cannot display the entire application.
I wanted to also note that if I refresh my page, everything works as expected. Does this mean something isn't initializing correctly?
this is the code specific to the page i am talking about:
<template>
<div class="member-info-carousel">
<div class="header">
<h2 v-if="founderChairman === true">Member List One</h2>
<h2 v-else>Member List Two</h2>
<img src="../assets/logo.png" alt="Logo" />
</div>
<carousel :minSwipeDistance="384" :perPage="1" :paginationEnabled="false" :navigationEnabled="true" navigationNextLabel="<i>NEXT</i>"
navigationPrevLabel="<i>BACK</i>" :navigateTo="selectedListIndex" #pagechange="OnPageChange">
<slide v-for="(member, index) in selectedList" :key="index">
<div class="member-bio-page" :member="member" v-on:showContent="showContent">
<div class="bio">
<div class="portrait-image">
<img :src="member.imgSrc" />
</div>
<div class="bio-container">
<div class="inner-scroll" v-bind:style="{top: scrollVar + 'px'}">
<div class="english"></div>
<div class="pin-name">
<img :src="member.pin" />
<h1>{{ member.name }}</h1>
</div>
<div class="description-container">
<div class="para">
<p class="quote" v-html="member.quote"></p>
<p v-html="member.bio"></p>
<div class="spanish"></div>
<p class="quote" v-html="member.spanishQuote"></p>
<p v-html="member.spanishBio"></p>
</div>
</div>
</div>
</div>
<div class="scroll-buttons">
<div>
<!-- set the class of active is the scroll variable is less than 0-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar < 0 }" #click="scrollUp" src="#/assets/arrow-up.png">
</div>
<div>
<!-- set the class of active is the scroll variable is greater than the height of the scrollable inner container-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar > pageChangeHeight }" #click="scrollDown" src="#/assets/arrow-down.png">
</div>
</div>
<div class="eng-span">
English
Español
</div>
</div>
<div class="play-button">
<!-- if the array members has a property of video, then the play button will show on the slide. If not it will not show the image -->
<img v-if="member.hasOwnProperty('video')" #click="showContent" src="#/assets/play-button.png">
</div>
</div>
<!-- <MemberBioPage :member="member" v-on:showContent="showContent"/> -->
</slide>
</carousel>
<modal name="video-modal"
:width="1706"
:height="960">
<video width="1706" height="960" :src="(selectedList && selectedList[this.currentPage]) ? selectedList[this.currentPage].video : ''" autoplay />
</modal>
<div class="footer-controls">
<div class="footer-bar">
<p>Tap Back or Next to view additional profiles.</p>
<p>Tap the arrows to scroll text up or down.</p>
</div>
<div class="nav-container">
<img class="nav-bubble" src="#/assets/navigation-bubble-bio-page.png" alt="An image where the back, next and close button sit" />
</div>
<button class="close-button" #click="closeInfo">
<img src="#/assets/x-close-button.png" />
CLOSE
</button>
</div>
</div>
</template>
<script>
import { Carousel, Slide } from 'vue-carousel'
export default {
data () {
return {
currentPage: 0,
pageChangeHeight: -10,
scrollVar: 0
}
},
components: {
// MemberBioPage,
Carousel,
Slide
},
mounted () {
this.enableArrows()
},
updated () {
this.enableArrows()
},
computed: {
selectedList () {
return this.$store.state.selectedList
},
selectedListIndex () {
return this.$store.state.selectedListIndex
},
founderChairman () {
return this.$store.state.founderChairman
}
},
methods: {
enableArrows () {
var outerHeight
var innerHeight
if (document.querySelectorAll('.VueCarousel-slide-active').length > 0) {
outerHeight = document.querySelectorAll('.VueCarousel-slide-active .bio-container')[0].clientHeight
innerHeight = document.querySelectorAll('.VueCarousel-slide-active .inner-scroll')[0].clientHeight
} else {
outerHeight = document.querySelectorAll('.VueCarousel-slide .bio-container')[0].clientHeight
innerHeight = document.querySelectorAll('.VueCarousel-slide .inner-scroll')[0].clientHeight
}
this.pageChangeHeight = outerHeight - innerHeight
return this.pageChangeHeight
},
scrollUp () {
this.scrollVar += 40
console.log(this.scrollVar += 40)
},
scrollDown () {
this.scrollVar -= 40
console.log(this.scrollVar)
},
OnPageChange (newPageIndex) {
this.scrollVar = 0
this.currentPage = newPageIndex
this.pageChangeHeight = -10
},
closeInfo () {
if (this.$store.state.selectedList === this.$store.state.foundersList) {
this.$store.commit('setSelectedState', this.$store.state.foundersList)
this.$router.push({ name: 'Carousel' })
} else if (this.$store.state.selectedList === this.$store.state.chairmanList) {
this.$store.commit('setSelectedState', this.$store.state.chairmanList)
this.$router.push({ name: 'Carousel' })
}
},
showContent () {
this.$modal.show('video-modal')
},
toEnglish () {
this.scrollVar = 0
},
toSpanish () {
var spanishPos
if (document.querySelectorAll('.VueCarousel-slide-active').length > 0) {
spanishPos = document.querySelectorAll('.VueCarousel-slide-active .spanish')[0].offsetTop
} else {
spanishPos = document.querySelectorAll('.VueCarousel-slide .spanish')[0].offsetTop
}
this.scrollVar = -spanishPos
}
}
}
</script>
This is my store index file:
import Vue from 'vue'
import Vuex from 'vuex'
import chairmans from '#/data/chairmans-club'
import founders from '#/data/founders-circle'
import memoriam from '#/data/in-memoriam'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
finishedLoading: false,
transitioning: false,
foundersList: founders,
chairmanList: chairmans,
selectedList: founders,
selectedListIndex: -1,
founderChairman: true,
inMemoriam: memoriam,
idleTimer: {
id: null,
duration: 1
},
idleTimeoutModal: {
show: false,
duration: 1
}
},
mutations: {
setSelectedState (state, list) {
state.selectedList = list
},
setSelectedListIndex (state, idx) {
state.selectedListIndex = idx
},
showIdleTimeoutModal (state, value) {
state.idleTimeoutModal.show = value
},
founderChairmanClicked (state, data) {
state.founderChairman = data
},
setInMemoriam (state, content) {
state.inMemoriam = content
}
},
actions: {
restartIdleTimer ({ state, commit }) {
clearTimeout(state.idleTimer.id)
state.idleTimer.id = setTimeout(() => {
commit('showIdleTimeoutModal', true)
}, state.idleTimer.duration * 1000)
},
stopIdleTimer ({ state }) {
clearTimeout(state.idleTimer.id)
}
}
})
export default store
and an example of the data i am pulling:
const event = [
{
index: 0,
name: 'Member Name',
carouselImage: require('#/assets/carousel-images/image.jpg'),
drawerImage: require('#/assets/drawer-images/drawerimage.jpg'),
imgSrc: require('#/assets/bio-images/bioimage.jpg'),
quote: '“quote.”',
spanishQuote: `“spanish quote.”`,
bio: '<p>bio copy here</p>',
spanishBio: '<p>spanish bio copy</p>',
pin: require('#/assets/pin.png')
}
]
export default event

Pagination Component not rendered on UI - React

I am trying to implement pagination in my react application using this guide I created the Pagination.js file as instructed in the guide, but I am not able to see that on my UI, here is the screenshot of the application
Here is my Search Results Page where I am implementing pagination, basically this will show the results fetched from the server based on user entered keyword and hence I want to show as paginated results. My js file corresponding to the above screenshot is:
import React from 'react';
import NavigationBar from './NavigationBar';
import SearchPageResultsStyle from "../assets/css/SearchResultsPage.css"
import Pagination from './Pagination';
class SearchResultsPage extends React.Component{
constructor(props) {
super(props);
console.log("Printing in the results component: this.props.location.state.data.keyword")
console.log(this.props.location.state.data.keyword)
this.state = {
results: this.props.location.state.data.results,
keyword: this.props.location.state.data.keyword,
pageOfItems: []
};
this.onChangePage = this.onChangePage.bind(this);
}
onChangePage(pageOfItems) {
// update local state with new page of items
this.setState({pageOfItems});
}
render() {
return(
<div>
<NavigationBar/>
<h4 style={{textAlign:'center', color:'#1a0dab'}}>Showing search results for <span style={{fontWeight:'bold', fontStyle:'Italic'}}>'{this.state.keyword}'</span></h4>
<hr/>
<div className={'wrap'} style={SearchPageResultsStyle}>
<div className={'fleft'}>left column</div>
<div className={'fcenter'}>
<h3 style={{color:'#1a0dab'}}>Tweeter tweets text will be displayed here!!!</h3>
<a href={'https://google.com'}>Tweet urls will be displayed here</a>
<br/>
<div style={{display:'inline'}}>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}}>topic: </span>crime</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}}>city: </span>delhi</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}}>lang: </span>Hindi</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}}>Hashtags: </span></p>
<hr/>
<Pagination items={this.state.results} onChangePage={this.onChangePage}/>
</div>
</div>
<div className={'fright'}>right column</div>
</div>
</div>
)
}
}
export default SearchResultsPage;
My pagination.js file
import React from 'react';
import PropTypes from 'prop-types';
const propTypes = {
items: PropTypes.array.isRequired,
onChangePage: PropTypes.func.isRequired,
initialPage: PropTypes.number,
pageSize: PropTypes.number
};
const defaultProps = {
initialPage: 1,
pageSize: 10
};
class Pagination extends React.Component{
constructor(props){
super(props);
this.state = {
pager: {}
};
// set page if items array isn't empty
if (this.props.items && this.props.items.length) {
this.setPage(this.props.initialPage);
}
}
componentDidUpdate(prevProps, prevState) {
// reset page if items array has changed
if (this.props.items !== prevProps.items) {
this.setPage(this.props.initialPage);
}
}
setPage(page) {
var { items, pageSize } = this.props;
var pager = this.state.pager;
if (page < 1 || page > pager.totalPages) {
return;
}
// get new pager object for specified page
pager = this.getPager(items.length, page, pageSize);
// get new page of items from items array
var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
// update state
this.setState({ pager: pager });
// call change page function in parent component
this.props.onChangePage(pageOfItems);
}
getPager(totalItems, currentPage, pageSize) {
// default to first page
currentPage = currentPage || 1;
// default page size is 10
pageSize = pageSize || 10;
// calculate total pages
var totalPages = Math.ceil(totalItems / pageSize);
var startPage, endPage;
if (totalPages <= 10) {
// less than 10 total pages so show all
startPage = 1;
endPage = totalPages;
} else {
// more than 10 total pages so calculate start and end pages
if (currentPage <= 6) {
startPage = 1;
endPage = 10;
} else if (currentPage + 4 >= totalPages) {
startPage = totalPages - 9;
endPage = totalPages;
} else {
startPage = currentPage - 5;
endPage = currentPage + 4;
}
}
// calculate start and end item indexes
var startIndex = (currentPage - 1) * pageSize;
var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
// create an array of pages to ng-repeat in the pager control
var pages = [...Array((endPage + 1) - startPage).keys()].map(i => startPage + i);
// return object with all pager properties required by the view
return {
totalItems: totalItems,
currentPage: currentPage,
pageSize: pageSize,
totalPages: totalPages,
startPage: startPage,
endPage: endPage,
startIndex: startIndex,
endIndex: endIndex,
pages: pages
};
}
render() {
var pager = this.state.pager;
if (!pager.pages || pager.pages.length <= 1) {
// don't display pager if there is only 1 page
return null;
}
return (
<div>
<ul className="pagination">
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<button onClick={() => this.setPage(1)}>First</button>
</li>
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<button onClick={() => this.setPage(pager.currentPage - 1)}>Previous</button>
</li>
{pager.pages.map((page, index) =>
<li key={index} className={pager.currentPage === page ? 'active' : ''}>
<button onClick={() => this.setPage(page)}>{page}</button>
</li>
)}
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<button onClick={() => this.setPage(pager.currentPage + 1)}>Next</button>
</li>
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<button onClick={() => this.setPage(pager.totalPages)}>Last</button>
</li>
</ul>
</div>
);
}
}
Pagination.propTypes = propTypes;
Pagination.defaultProps = defaultProps;
export default Pagination;
I do not understand that why my list of items in Pagination.js file is not getting rendered.
Can anybody point out what exactly is it that I am missing?
Your issue is a misplaced if statement in the constructor. So this:
class Pagination extends React.Component{
constructor(props){
super(props);
this.state = {
pager: {}
};
// set page if items array isn't empty
if (this.props.items && this.props.items.length) {
this.setPage(this.props.initialPage);
}
}
Should be:
class Pagination extends React.Component{
constructor(props){
super(props);
this.state = {
pager: {}
}
}
componentWillMount() {
if (this.props.items && this.props.items.length) {
this.setPage(this.props.initialPage);
}
}
This is how I implemented the above library, it's really cool library. I have to add css to it, to make it look good. It is working for me now.
import React from 'react';
import NavigationBar from './NavigationBar';
import SearchPageResultsStyle from "../assets/css/SearchResultsPage.css"
import Pagination from './Pagination';
class SearchResultsPage extends React.Component{
constructor(props) {
super(props);
console.log("Printing in the results component: this.props.location.state.data.results")
console.log(this.props.location.state.data.results)
this.state = {
results: this.props.location.state.data.results,
keyword: this.props.location.state.data.keyword,
pageOfItems: []
};
this.onChangePage = this.onChangePage.bind(this);
}
onChangePage(pageOfItems) {
// update local state with new page of items
this.setState({pageOfItems});
}
render() {
const renderItems = this.state.pageOfItems.map((item, index) => {
return (
<div>
<h3 style={{color: '#1a0dab'}} key={index}>{item.text}</h3>
<a href={'https://google.com'} key={index}>{item.tweetUrl}</a>
<br/>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>topic: </span>{item.topic}</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>city: </span>{item.city}</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>lang: </span>{item.lang}</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>Hashtags: </span></p>
<hr/>
</div>
)
})
return (
<div>
<NavigationBar/>
<h4 style={{textAlign:'center', color:'#1a0dab'}}>Showing search results for <span style={{fontWeight:'bold', fontStyle:'Italic'}}>'{this.state.keyword}'</span></h4>
<hr/>
<div className={'wrap'} style={SearchPageResultsStyle}>
<div className={'fleft'}>left column</div>
<div className={'fcenter'}>
{renderItems}
<Pagination items={this.state.results} onChangePage={this.onChangePage}/>
</div>
</div>
<div className={'fright'}></div>
</div>
)
}
}
export default SearchResultsPage;

Categories