How can i paginate table - react-native

I have the following code to display data from json file, i have more that 500 records i want to display 10 records per page. Here is my project in [code pen][1] . I tried react-pagination library but that doesn't work. what is the best way to do this? Open to use any library recommended -- i tried almost all of them.
here is how my code looks like

I'm sure there are a hundred different ways of doing it, but just to teach the idea of the mechanics, here is a very manual version:
{this.state.filteredData
.slice(this.state.activePage * 10, (this.state.activePage + 1) * 10)
.map(results => ( ...
))}
.....
{/*Pagination goes here */}
<button onClick={() => {this.setState({activePage: this.state.activePage - 1})}} >
prev</button>
<button onClick={() => {this.setState({activePage: this.state.activePage + 1})}} >
next</button>
That is, you take only a slice of the data before mapping it into DOM elements, and the buttons for advancing or going back just select the slice by setting the activePage state variable you already had.

You could have something along the lines of an index and offset and then create chunks of your array.
Give this a try:
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import cardData from "./response.json";
import "./style.css";
class App extends Component {
constructor() {
super();
const offset = 5;
console.log(cardData);
this.state = {
name: "React",
index: 0,
offset,
chunks: this.chunkArray(cardData.data.Table, offset)
};
}
chunkArray(inputArray, chunkSize){
console.log("inputArray:: ", inputArray);
const results = [];
while (inputArray.length) {
results.push(inputArray.splice(0, chunkSize));
}
console.log("results:: ", results);
return results;
}
handleClick(index) {
this.setState({
index
})
}
render() {
console.log(this.state.chunks);
return (
<div>
{this.state.chunks && this.state.chunks[this.state.index].map(results => (
<div className="col-sm-3">
<h3>
{results.first_name} {results.last_name}
</h3>
<h3>{results.manager}</h3>
<div className="row">
<div className="col-md-3 col-sm-6"> {results.Department}</div>
</div>
<a
to={{ pathname: `/cards/${results.id}`, state: results }}
className={`card-wrapper restore-${results.id}`}
href={`/cards/${results.id}`}
>
View Detail
</a>
</div>
))}
<br />
{ this.state.chunks && this.state.chunks.map((item, index) => <button onClick={() => this.handleClick(index)}>{index + 1}</button>) }
</div>
);
}
}
render(<App />, document.getElementById("root"));
Here's a Working Code Sample Demo for your ref.

If you're using hooks, this will work otherwise it can be easily adapted. Basically, just store the index of where you are and then get the data you need based on that index:
const [index, setIndex] = React.useState(0);
const PAGE_SIZE = 10;
const tableData = cardData.data.Table.slice(index, index + PAGE_SIZE);
const table = {tableData.map(results => (
<div className="col-sm-3">
<h3>
{results.first_name} {results.last_name}
</h3>
<h3 >{results.manager}</h3>
<div className="row">
<div className="col-md-3 col-sm-6"> {results.Department}</div>
</div>
<Link
to={{ pathname: `/cards/${results.id}`, state: results }}
className={`card-wrapper restore-${results.id}`}
>
View Detail
</Link>
</div>
))}
const navigation = (
<div>
<div disabled={index <= 0 ? true : false} onClick={() => setIndex(index - PAGE_SIZE)}>Prev</div>
<div disabled={index <= cardData.data.Table.length ? true : false} onClick={() => setIndex(index + PAGE_SIZE)}>Next</div>
</div>
);

Related

Wrong site size in Vue

Hi I'm currently learning Vue but I've noticed that for some reason all my sites have the wrong size, as if the default mode was center and small, I haven't touched any setting that I'm aware of, see pics for examples, notice the huge viewport compared to the info that is shown:
This one is almost right, apparently got the heighht right but the width wrong, I have no idea why
This one is at the center for some reason
This one is the worst, look at how tiny it is, like what the hell
Any help would be appreicated, thanks!
I've tried tinkering a bit with CSS margins, height, widht, ect., but nothing really works, it only gets worse
I'll provide a code example of the second case, the simplest one:
<script setup>
import { ref, computed } from 'vue';
const name = 'Vue Dinámico';
const counter = ref(0);
const colorRed = "color: red";
const colorGreen = "color: green";
const increment = () => {
counter.value++;
};
const decrement = () => {
counter.value--;
};
const reset = () => {
counter.value = 0;
};
const classCounter = computed(() => {
if(counter.value === 0){
return 'zero';
}
if(counter.value > 0) {
return 'positive';
}
if(counter.value < 0){
return 'negative';
}
});
const arrayNum = ref([]);
const addNum = () => {
arrayNum.value.push(counter.value);
};
const bloquearBtnAdd = computed(() => {
const numSearch = arrayNum.value.find(num => num === counter.value);
console.log(numSearch);
//if(numSearch === 0) return true;
//return numSearch ? true : false;
return numSearch || numSearch === 0;
})
</script>
<template>
<div class="container text-center mt-3">
<h1>Hola {{ name.toUpperCase() }}</h1>
<h2 :class="classCounter">{{ counter }}</h2>
<div class="btn-group">
<button #click="increment" class="btn btn-success">Aumentar</button>
<button #click="decrement" class="btn btn-danger">Disminuir</button>
<button #click="reset" class="btn btn-sceondary">Reset</button>
<button #click="addNum" :disabled="bloquearBtnAdd" class="btn btn-primary">Agregar</button>
</div>
<ul class="list-group mt-4">
<li
class="list-group-item"
v-for="(num, index) in arrayNum"
:key="index">
{{num}}
</li>
</ul>
</div>
</template>
<style>
h1 {
color: red;
}
.positive {
color: green;
}
.negative {
color: red;
}
.zero {
color: peru;
}
</style>

Why the text isn’t updated in Vue3?

I’m trying to display a name dynamically, but I get the same name forEach element. What I’m trying to do is:
<template>
<div class="app__projects">
<div
class="app__projects__container"
v-for="project in visibleProjects"
:key="project.id"
:id="project.id"
>
<div class="app__projects__image">
<img
:src="project.imgUrl"
alt="Project Image"
width="570"
height="320"
loading="lazy"
/>
</div>
<div class="app__projects__content">
<h3>{{ project.name }}</h3>
<p>
{{ project.description }}
</p>
<a
:href="project.link"
target="_blank"
class="app__projects__content-btn"
>
{{ displayNameButton }}
</a>
<hr class="app__projects__content--spacer" />
</div>
</div>
<button
v-if="showMoreProjectsButton"
class="app__projects__showMoreButton"
#click="loadMoreProjects"
>
show more projects
</button>
</div>
</template>
On the I'm trying to display a name dynamically, and all the time the same name is displayed, but I want to display the name based on the computed property that I wrote below.
Here is the visibleProjects:
const visibleProjects = computed(() => {
return storeProjects.projects.slice(0, maxProjectsShown.value);
});
I’m trying to iterate through an array of objects from the store like:
const displayNameButton = computed(() => {
const isObjPresent = storeProjects.projects.find((o => o.wordpress === 'yes')).wordpress;
console.log(isObjPresent);
if (isObjPresent === 'yes') return 'See Website';
else if (!isObjPresent) return 'See code';
})
The array of objects from the store is:
import { defineStore } from 'pinia';
import { v4 as uuidv4 } from 'uuid';
export const useProjectsStore = defineStore({
id: 'projects',
state: () => {
return {
projects: [
{
id: uuidv4(),
imgUrl: lightImg,
name: 'use this',
description:
'track of this',
wordpress: false,
},
{
id: uuidv4(),
imgUrl: recogn,
name: 'deep lear',
description:
'I tried my best',
wordpress: ‘yes’,
},
...
{},
{},
],
};
},
});
So the problem is with your computed property. It will always return the same value because there is no input based on which the function can determine which string should it returns. Based on the code you already have I think you should write a method that will return desired string.
const displayNameButton = (project) => {
return (project.wordpress === 'yes') ? 'See Website' : 'See code';
})
and in the template
<a
:href="project.link"
target="_blank"
class="app__projects__content-btn"
>
{{ displayNameButton(project) }}
</a>
OR you can modify your visibleProjects:
const visibleProjects = computed(() => {
return storeProjects.projects.slice(0, maxProjectsShown.value).map((e) => {
const project = {...e};
project.wordpress = (project.wordpress === 'yes') ? 'See Website' : 'See code';
return project;
});
});
and in the template
<a
:href="project.link"
target="_blank"
class="app__projects__content-btn"
>
{{ project.wordpress }}
</a>

Vue 3, Pinia - child component is not updated when the store is updated

I have this Pinia store:
import { defineStore } from 'pinia'
import axiosClient from '#/axios'
export const useTableOrderStore = defineStore( 'tableOrders', {
id : 'tableOrders',
state: () => {
return {
tableOrders: []
}
},
actions: {
addToOrder(item, quantity)
{
const searchIndex = this.tableOrders.findIndex((order) => order.id == item.id);
if(searchIndex !== -1)
{
this.tableOrders[searchIndex].quantity += quantity
}
else
{
item.quantity = quantity
this.tableOrders.push(item)
}
}
}
})
Parent component:
<script setup>
import {ref} from "vue"
import {useTableOrderStore} from "#/store/tableOrder";
import CounterInput from "#/components/Inputs/Counter.vue"
const tableOrderStore = useTableOrderStore()
const props = defineProps(['product'])
let quantity = ref(1)
let addToOrder = (product) => {
tableOrderStore.addToOrder(product, quantity.value)
quantity.value = 1
}
</script>
<template>
<div class="input-group">
<counter-input :quantity="quantity"
#quantity-event="(n) => quantity = n"></counter-input>
<button class="btn btn-primary btn-sm ms-1" #click="addToOrder(product)">
Add <font-awesome-icon icon="fas fa-receipt" class="ms-2" />
</button>
</div>
</template>
Child component:
<script setup>
import {ref} from "vue"
let props = defineProps({
quantity: {
type: Number,
required: true
}
})
let count = ref(props.quantity)
let increase = () => {
count.value++
emit('quantityEvent', count.value)
}
let decrease = () =>
{
if(count.value === 1)
return
count.value--
emit('quantityEvent', count.value)
}
const emit = defineEmits(['quantityEvent'])
</script>
<template>
<span class="input-group-btn">
<button type="button"
class="btn btn-danger btn-number"
data-type="minus"
#click="decrease"
>
<font-awesome-icon icon="fas fa-minus-circle" />
</button>
</span>
<input type="text"
name="quantity"
:value="count"
class="form-control input-number"
min="1"
>
<span class="input-group-btn">
<button type="button"
class="btn btn-success btn-number"
data-type="plus"
#click="increase"
>
<font-awesome-icon icon="fas fa-plus-circle" />
</button>
</span>
</template>
The first time method addToOrder is fired, the product is correctly added and child product renders is.
The first issue here is that the quantity is set to 1, but it is not set in the child component.
The second problem is with the quantity - first addToOrder is ok, and quantity is shown correctly, but if new quantity is added the Pinia store is updated, but it is not reflected in the component. What am I doing wrong here?
I guess you run into an vuejs caveat.
this.tableOrders[searchIndex].quantity += quantity
Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue When you modify the length of the
array, e.g. vm.items.length = newLength
You directly set an item.
Instead, you could use .splice() to replace your item:
let newItem = {
...this.tableOrders[searchIndex],
quantity: this.tableOrders[searchIndex].quantity + quantity
};
//replace old item with new
this.tableOrders.splice(searchIndex, 1, newItem)
Here are the mutation methods that triggers an update:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
The first time you use addToOrders works because you used .push() witch is one of the mutations that triggers the re-render.
First issue, i dont know how props.quantity is not set in the child component. Try console props.quantity right after you defined props if it displayed the result as you want then try to console it inside watch method. If props.quantity has changed but your child component is not update then your child component somehow not updated. You can try to force update it and here's how: https://medium.com/emblatech/ways-to-force-vue-to-re-render-a-component-df866fbacf47 (Using the key changing technique)
Second issue, i think this one #quantity-event="(n) => quantity = n" should be #quantity-event="(n) => { quantity = n }"

Having problems calling an API id

Hi I am having some problems figuring out how to access an id. I am making a twitter cloner and I have an Icon I would like to click and see what people are commenting on it. But I have hit a wall and cant figure out how to access the Id when the chatbubble is clicked.
Any help would be greatly appreciated. The API works perfectly and I can call an id through postman.
const GetData = (id) => {
axios.get('https://localhost:44368/api/users/{id}').then((response) => {
console.log(response.data, "list of heroes ");
});
};
return (
<div className="post">
<div className="ppictur">
<Avatar src={avatar} />
</div>
<div className="post_body">
<div className="post_header">
<div className="post_headerText">
<h3>
{displayName}
<span className="post_headerSpecial">
<VerifiedIcon className="post_badge" />
#{username}
</span>
</h3>
</div>
<div className="post_headerDesription">
<p>{text}</p>
</div>
</div>
<img src={image} alt="" />
<div className="post_footer">
<ChatBubbleOutlineIcon onClick={GetData()} />
<RepeatIcon fontSize="small" />
<FavoriteBorderIcon fontSize="small" />
<PublishOutlinedIcon fontSize="small" />
</div>
</div>
</div>
);
}
export default Post;
const [posts, setPosts] = useState([]);
useEffect(() => {
axios.get('https://localhost:44368/api/users').then((response) => {
console.log(response.data, "list of heroes ");
setPosts(response.data);
});
}, []);
const icon = document.getElementById("Dark");
function DarkM() {
document.body.classList.toggle("dark-theme");
}
return (
<div className="commentbox">
<div className="header">
<h2>Home</h2>
<DarkModeOutlinedIcon id="Dark" onClick={() => DarkM(icon)} />
</div>
<Opinion />
{posts.map(post => (
<Post
avatar={post.profilePicture}
displayName={post.name}
username={post.userName}
text={post.post}
image={post.image}
bull
/>
)).reverse()}
</div>
);
}
export default Feed; ```
Use template literal ES6 with backticks.
const GetData = (id) => {
axios.get(`https://localhost:44368/api/users/${id}`).then((response) => {
console.log(response.data, "list of heroes ");
});
};
Also when you call it, make sure to pass arguments.
<ChatBubbleOutlineIcon onClick={GetData(9)} />
In my other component i wasnt pushing all the data through. that is my props didnt know what i was trying to call
const objectToPass = {
postId, avatar, displayName, username, text, image
}
const showSingleData = (value) => {
navigate(`/tweet/${value.postId}`)
console.log(value)
}```
it was a problem with my other component

Custom Gutenberg Block with Slider

I'm creating a Gutenberg block for a slider using Boostrap. I can't figure out how I can go about inserting the "active" class only on the first post inside the loop, any suggestions would be appreciated, thanks.
This is my Edit file:
import { Component, RawHTML } from "#wordpress/element";
import { RichText, BlockControls, InspectorControls, AlignmentToolbar} from "#wordpress/editor";
import { __ } from "#wordpress/i18n";
import { withSelect } from "#wordpress/data";
import { decodeEntities } from "#wordpress/html-entities";
import { Toolbar, PanelBody, BaseControl, ColorPicker, FontSizePicker, RangeControl, TextControl, SelectControl } from "#wordpress/components";
import { dateI18n, format, __experimentalGetSettings } from '#wordpress/date';
class SliderEdit extends Component {
onChangeCategories = (categories) => {
this.props.setAttributes({postCategories: categories.join(',')})
}
onChangeNumberOfPosts = (numberOfPosts) => {
this.props.setAttributes({numberOfPosts})
}
render() {
const { className, attributes, setAttributes, categories, posts} = this.props;
const {
postCategories,
numberOfPosts,
} = attributes;
const dateFormat = __experimentalGetSettings().formats.date;
return(
<>
<InspectorControls>
<PanelBody
title={__('Loop Settings', 'df-slider-b')}
>
<div class="df-cat-multiple">
<SelectControl
multiple
label={__("Categories","df-blocks")}
help={__('You can select multiple categories!','df-blocks')}
onChange={this.onChangeCategories}
options={categories && categories.map(category => ({value: category.id, label: category.name}))}
value={postCategories && postCategories.split(',')}
/>
</div>
<RangeControl
label={__("Number of Posts","df-blocks")}
help={__('Set -1 to get all posts','df-blocks')}
value={ numberOfPosts }
onChange={ this.onChangeNumberOfPosts }
min={-1}
max={10}
/>
</PanelBody>
</InspectorControls>
{(posts && posts.length > 0) ?
<div id="carouselDFControls" class="df_height_carousel_block carousel slide" data-ride="carousel">
<div class="carousel-inner">
{posts.map( post=> (
<>
{post && post._embedded && post._embedded['wp:featuredmedia'] &&
<div class="carousel-item active">
<img src={ post._embedded['wp:featuredmedia'][0].source_url } />
</div>
}
</>
))}
<a class="carousel-control-prev df-carousel-control-prev" href="#carouselDFControls" role="button" data-slide="prev">
<i class="icon-arrow-left"></i>
</a>
<a class="carousel-control-next df-carousel-control-next" href="#carouselDFControls" role="button" data-slide="next">
<i class="icon-arrow-right"></i>
</a>
</div>
</div>
: <div>{posts ? __("No posts found","df-blocks") : __("Loading...","df-blocks")}</div>
}
</>
)
}
}
export default withSelect(
(select, props) => {
const { attributes } = props;
const { numberOfPosts, postCategories } = attributes;
let query = { per_page: numberOfPosts}
if(postCategories) {
query['categories'] = postCategories;
}
return {
posts: select('core').getEntityRecords('postType', 'post',{_embed: true} ),
posts: select('core').getEntityRecords('postType', 'post', query ),
categories: select('core').getEntityRecords('taxonomy','category', {per_page: -1})
}
}
)(SliderEdit);
If I don't add the "active" class in the first post the carousel doesn't work.
Regards
Denis
You can use the index param in your map function. If the index is 0 it is the first item in the loop.
{ posts.map( ( post, index ) => (
<div className={ `carousel-item${ index === 0 ? ' active' : '' }` }>
...
</div>
) }
Also, you want to use className instead of class in React.