Implement pagination using Link with rel 'next' and 'prev'
authorPhilippe Pepiot <philippe.pepiot@logilab.fr>
Tue, 06 Jun 2017 16:50:39 +0200
changeset 224 13f568434dcd
parent 223 b7000ff42372
child 225 79e8794592ec
Implement pagination using Link with rel 'next' and 'prev' Add a `PaginationLinks` component that render Previous and Next button based on HTTP Link header. Add a higher-order component `withPagination` which wraps any component to add `PaginationLinks` on it.
src/components/BaseViews.js
--- a/src/components/BaseViews.js	Tue Jun 06 17:45:41 2017 +0200
+++ b/src/components/BaseViews.js	Tue Jun 06 16:50:39 2017 +0200
@@ -38,6 +38,53 @@
     collection: PropTypeJsonaryWrapper.isRequired,
 };
 
+export function PaginationLinks(props) {
+    function render(rel) {
+        const link = props.links.rel(rel);
+        let title = null;
+        if (rel === 'prev') {
+            title = <span><span aria-hidden="true">&larr;</span> Previous</span>;
+        } else {
+            title = <span>Next <span aria-hidden="true">&rarr;</span></span>;
+        }
+        if (link.length > 0) {
+            return (
+                <li><a href="javascript:void(0)" onClick={() => props.changeRoute(link[0].uri)}>
+                    {title}</a></li>
+            );
+        } else {
+            return <li className="disabled">{title}</li>;
+        }
+    }
+    if (props.links.rel('prev').length > 0 || props.links.rel('next').length > 0) {
+        return <ul className="pager">{render('prev')}&nbsp;{render('next')}</ul>;
+    } else {
+        return null;
+    }
+}
+
+PaginationLinks.propTypes = {
+    links: PropTypes.object.isRequired,
+    changeRoute: PropTypes.func.isRequired,
+};
+
+export function withPagination(WrappedComponent) {
+    const wrapper = function(props) {
+        return (
+            <div className={props.className}>
+                <WrappedComponent {...props} />
+                <PaginationLinks changeRoute={props.changeRoute} links={props.resource.links} />
+            </div>
+        );
+    };
+    wrapper.propTypes = {
+        resource: PropTypesResourceModel.isRequired,
+        changeRoute: PropTypes.func.isRequired,
+        className: PropTypes.string,
+    };
+    return wrapper;
+}
+
 export function ActionsDropDown({target, ignore = []}) {
     const actions = target.allowedActions.filter(x => !ignore.includes(x));
     if (isEmpty(actions)) {