Pagination working

pull/52/head
Piero Toffanin 2016-11-26 10:27:54 -05:00
rodzic 511f5b8680
commit ec74ab6def
7 zmienionych plików z 100 dodań i 28 usunięć

Wyświetl plik

@ -48,7 +48,7 @@ class Dashboard extends React.Component {
ref={(domNode) => { this.projectDialog = domNode; }} ref={(domNode) => { this.projectDialog = domNode; }}
/> />
<ProjectList <ProjectList
source="/api/projects/?ordering=-created_at&page=1" source="/api/projects/?ordering=-created_at&page=#{PAGE}"
ref={(domNode) => { this.projectList = domNode; }} /> ref={(domNode) => { this.projectList = domNode; }} />
</div> </div>
); );

Wyświetl plik

@ -60,7 +60,8 @@ class EditProjectDialog extends React.Component {
} }
componentWillUnmount(){ componentWillUnmount(){
$(this.modal).off('hidden.bs.modal hidden.bs.modal'); $(this.modal).off('hidden.bs.modal hidden.bs.modal')
.modal('hide');
} }
componentDidUpdate(){ componentDidUpdate(){

Wyświetl plik

@ -2,7 +2,7 @@ import React from 'react';
import '../css/Map.scss'; import '../css/Map.scss';
import 'leaflet/dist/leaflet.css'; import 'leaflet/dist/leaflet.css';
import Leaflet from 'leaflet'; import Leaflet from 'leaflet';
import async from 'async/dist/async'; import async from 'async';
import 'leaflet-measure/dist/leaflet-measure.css'; import 'leaflet-measure/dist/leaflet-measure.css';
import 'leaflet-measure/dist/leaflet-measure'; import 'leaflet-measure/dist/leaflet-measure';
import '../vendor/leaflet/L.Control.MousePosition.css'; import '../vendor/leaflet/L.Control.MousePosition.css';

Wyświetl plik

@ -1,28 +1,80 @@
import React from 'react'; import React from 'react';
import update from 'react-addons-update';
/*abstract*/ class Paginated extends React.Component{ /*abstract*/ class Paginated extends React.Component{
constructor(){ constructor(){
super(); super();
} }
setupPagination(itemsPerPage, totalItems){ updatePagination(itemsPerPage, totalItems){
let currentPage = 1; let currentPage = 1;
const totalPages = this.totalPages(itemsPerPage, totalItems);
if (this.state.pagination && this.state.pagination.currentPage !== undefined){ if (this.state.pagination && this.state.pagination.currentPage !== undefined){
currentPage = this.state.pagination.currentPage; currentPage = this.state.pagination.currentPage;
} }
if (currentPage > totalPages) currentPage = totalPages;
this.setState({pagination: { this.setState({pagination: {
itemsPerPage: itemsPerPage, switchingPages: false,
totalItems: totalItems, itemsPerPage: itemsPerPage,
currentPage: currentPage totalItems: totalItems,
currentPage: currentPage
} }
}); });
this.handlePageChange = this.handlePageChange.bind(this);
} }
getPaginatedUrl(base, page){ totalPages(itemsPerPage, totalItems){
return Math.ceil(totalItems / itemsPerPage);
}
getPaginatedUrl(base){
const page = this.state.pagination && this.state.pagination.currentPage !== undefined
? this.state.pagination.currentPage
: 1;
return base.replace(/#\{PAGE\}/g, page); return base.replace(/#\{PAGE\}/g, page);
} }
setPaginationState(props, done){
this.setState(update(this.state, {
pagination: {
$merge: props
}
}), done);
}
handlePageChange(pageNum){
return (e) => {
// Update current page, once rendering is completed, raise
// on page changed event
this.setPaginationState({
currentPage: pageNum,
switchingPages: true
}, () => {
if (this.onPageChanged) this.onPageChanged(pageNum);
});
}
}
handlePageItemsNumChange(delta, needsRefreshCallback){
const pagesBefore = this.totalPages(this.state.pagination.itemsPerPage, this.state.pagination.totalItems),
pagesAfter = this.totalPages(this.state.pagination.itemsPerPage, this.state.pagination.totalItems + delta);
let currentPage = this.state.pagination.currentPage;
if (currentPage > pagesAfter) currentPage = pagesAfter;
this.setPaginationState({
totalItems: this.state.pagination.totalItems + delta,
currentPage: currentPage
}, () => {
if (pagesBefore !== pagesAfter) needsRefreshCallback(pagesAfter);
});
}
render(){ render(){
throw new Error("Override me"); throw new Error("Override me");
} }

Wyświetl plik

@ -14,7 +14,7 @@ class Paginator extends React.Component {
<div className={this.props.className}> <div className={this.props.className}>
<ul className="pagination pagination-sm"> <ul className="pagination pagination-sm">
<li className={currentPage === 1 ? "disabled" : ""}> <li className={currentPage === 1 ? "disabled" : ""}>
<a href="#"> <a href="javascript:void(0);" onClick={this.props.handlePageChange(1)}>
<span>&laquo;</span> <span>&laquo;</span>
</a> </a>
</li> </li>
@ -22,10 +22,10 @@ class Paginator extends React.Component {
return (<li return (<li
key={page + 1} key={page + 1}
className={currentPage === (page + 1) ? "active" : ""} className={currentPage === (page + 1) ? "active" : ""}
><a href="#">{page + 1}</a></li>); ><a href="javascript:void(0);" onClick={this.props.handlePageChange(page + 1)}>{page + 1}</a></li>);
})} })}
<li className={currentPage === numPages ? "disabled" : ""}> <li className={currentPage === numPages ? "disabled" : ""}>
<a href="#"> <a href="javascript:void(0);" onClick={this.props.handlePageChange(numPages)}>
<span>&raquo;</span> <span>&raquo;</span>
</a> </a>
</li> </li>

Wyświetl plik

@ -1,9 +1,11 @@
import React from 'react'; import React from 'react';
import $ from 'jquery'; import $ from 'jquery';
import '../css/ProjectList.scss';
import ProjectListItem from './ProjectListItem'; import ProjectListItem from './ProjectListItem';
import Paginated from './Paginated'; import Paginated from './Paginated';
import Paginator from './Paginator'; import Paginator from './Paginator';
import ErrorMessage from './ErrorMessage';
class ProjectList extends Paginated { class ProjectList extends Paginated {
constructor(){ constructor(){
@ -11,10 +13,13 @@ class ProjectList extends Paginated {
this.state = { this.state = {
loading: true, loading: true,
refreshing: false,
error: "", error: "",
projects: null projects: []
} }
this.PROJECTS_PER_PAGE = 10;
this.handleDelete = this.handleDelete.bind(this); this.handleDelete = this.handleDelete.bind(this);
} }
@ -23,15 +28,17 @@ class ProjectList extends Paginated {
} }
refresh(){ refresh(){
this.setState({refreshing: true});
// Load projects from API // Load projects from API
this.serverRequest = this.serverRequest =
$.getJSON(this.props.source, json => { $.getJSON(this.getPaginatedUrl(this.props.source), json => {
if (json.results){ if (json.results){
this.setState({ this.setState({
projects: json.results, projects: json.results,
loading: false loading: false
}); });
this.setupPagination(10, json.count); this.updatePagination(this.PROJECTS_PER_PAGE, json.count);
}else{ }else{
this.setState({ this.setState({
error: `Invalid JSON response: ${JSON.stringify(json)}`, error: `Invalid JSON response: ${JSON.stringify(json)}`,
@ -44,8 +51,14 @@ class ProjectList extends Paginated {
error: `Could not load projects list: ${textStatus}`, error: `Could not load projects list: ${textStatus}`,
loading: false loading: false
}); });
})
.always(() => {
this.setState({refreshing: false});
}); });
}
onPageChanged(pageNum){
this.refresh();
} }
componentWillUnmount(){ componentWillUnmount(){
@ -55,25 +68,25 @@ class ProjectList extends Paginated {
handleDelete(projectId){ handleDelete(projectId){
let projects = this.state.projects.filter(p => p.id !== projectId); let projects = this.state.projects.filter(p => p.id !== projectId);
this.setState({projects: projects}); this.setState({projects: projects});
this.handlePageItemsNumChange(-1, () => {
this.refresh();
});
} }
render() { render() {
if (this.state.loading){ if (this.state.loading){
return (<div>Loading projects... <i className="fa fa-refresh fa-spin fa-fw"></i></div>); return (<div className="project-list">Loading projects... <i className="fa fa-refresh fa-spin fa-fw"></i></div>);
}
else if (this.state.projects){
return (
<Paginator className="text-right" {...this.state.pagination}>
<ul className="list-group">
{this.state.projects.map(p => (
<ProjectListItem key={p.id} data={p} onDelete={this.handleDelete} />
))}
</ul>
</Paginator>);
}else if (this.state.error){
return (<div>An error occurred: {this.state.error}</div>);
}else{ }else{
return (<div></div>); // should never happen return (<div className="project-list">
<ErrorMessage bind={[this, 'error']} />
<Paginator className="text-right" {...this.state.pagination} handlePageChange={this.handlePageChange.bind(this)}>
<ul className={"list-group project-list " + (this.state.refreshing ? "refreshing" : "")}>
{this.state.projects.map(p => (
<ProjectListItem key={p.id} data={p} onDelete={this.handleDelete} />
))}
</ul>
</Paginator>
</div>);
} }
} }
} }

Wyświetl plik

@ -0,0 +1,6 @@
.project-list{
ul.project-list.refreshing{
opacity: 0.5;
pointer-events: none;
}
}