17.0.2 • Published 5 years ago

react-filteredlist v17.0.2

Weekly downloads
689
License
-
Repository
github
Last release
5 years ago

React Filteredlist

A very versatile Datalist component with filtering. It is very configurable with many hooks for utilizing the component's behaviors. More specific documentation to come.

Table of contents

Screenshots

Filteredlist w/ custom display component screenshot npm.io

Filteredlist w/ default text component screenshot npm.io

Development

To build the examples locally, run:

npm install
npm start

Then open localhost:8000 in a browser.

Installation

The easiest way to use react-filteredlist is to install it from NPM and include it in your own React build process (using Browserify, Webpack, etc).

You can also use the standalone build by including dist/react-filteredlist.js in your page. If you use this, make sure you have already included React, and it is available as a global variable.

npm i -S react-filteredlist

Usage

See that dataListConfig being passed into the config prop on the component usage in the below example? That is essentially a large object. At the end of the docs, you will find an example of a basic config object. Pop it in there and you should see a simple list running. What follows after this section are the details for building that config object in a more advanced way.

Note: The pushDispatch={Items: users.items, count: users.totalCount} prop is optional. If it's provided and passed data, then the list and pagination will prefer the data here for list rendering over incoming data via other sources. This behavior mimicks the pushDispatch hook for using socket based data pushes into the component. This prop is useful for when you want a record of your list items to come from your parent application's store. This way changes in the parent store will be propagated to the list. This is useful for orm based store structures.

Styles

It's important that the stylesheet be imported separately. In ES6, depending on your tooling, import directly into js otherwise use @import '../node_modules/react-filteredlist/dist/main.css'; in your stylesheet. Fix the path to point correctly to your node_modules folder.

const FilteredList = require('react-filteredlist');

<FilteredList config={dataListConfig} pushDispatch={Items: users.items, count: users.totalCount}/>

Or in ES6

import FilteredList from 'react-filteredlist';
import '../node_modules/react-filteredlist/dist/main.css';

<FilteredList config={dataListConfig} pushDispatch={Items: users.items, count: users.totalCount}/>

Breaking Changes

1. OnCheck hook arg is has been updated to {item: {}, items: [], checkedItems: [], action: checked/unchecked}
2. Since version 16.1.1 the need to import a stylesheet has been removed. Your app will throw an error now telling you it can't find the file to import. Just remove your stylesheet import for the filteredlist. JS takes care of this for you now.

This change gives visiblity to an array of items with a state of checked (checkedItems), the action on the item performed(add, update, remove) and the list of items mutated state.

Documentation

Top level configuration

This (in the example folder structure this is the top-level index.js file) is the entrypoint for pulling together all the datalist, views, filter groups, and filters configs.

PropertyTypeDefaultPossible ValuesDescription
idstring''''The UNIQUE id of the filteredlist component.
selectorstring''''Currently not used. @todo program in the custom selector option for the entire component.
defaultViewstring''''The UNIQUE id of the view to use by default. Matches the view's id property.
writeQueryStringToURLbooleanfalsetrue,falseIf true, the queries will be converted to query string params and written to the url.
runQueryStringURLOnRenderbooleanfalsetrue,falseIf true, when a filters query string is present in the url, the component will attempt to run it. This is necessary for sharing and in general for tracking internal state.
showFiltersbooleanfalsetrue,falseIf false, the filters sidebar willbe hidden.
filtersLabelstring''''A label for the filters sidebar.
pinPaginationbooleanfalsetrue,falseIf true, the pagination compnent will be position fixed to the bottom of the datalist.
notifyfunctionAccepts a function that gets passed 3 parameters (message, type, position). Use this to either console.log your notifications or pass them to the app's notification system, e.g. noty
headerobjectundefinedundefined,objectHeader options container.
header.titlestring''''A title for the entire component.
footerobjectundefinedundefined,objectCurrently not used but could contain footer specific options in the future.
dataListobjectundefinedundefined,objectThe datalist config object gets passed in here.
viewsarrayundefinedundefined,arrayThe views config objects array gets passed in here.
hooksobjectundefinedundefined,objectThe hooks config object gets passed in here.
graphqlobjectundefinedundefined,objectLEGACY. Currently not used. @todo: remove. The graphql config object gets passed in here.

Example

import dataList from './dataList';
import views from './views';
import hooks from './hooks';
import graphql from './graphql';

import { GOOGLE_UA_ID } from '../../config';
import utils from '../../';

export default {
  id: 'main',
  selector: '',
  defaultView: 'buyer',
  writeQueryStringToURL: true,
  runQueryStringURLOnRender: true,
  showFilters: true,
  filtersLabel: '',
  pinPagination: true,
  notify: (message, type, position) => { utils.notify({ message, level: type, position: 'tr' }); },
  header: {
    title: ''
  },
  footer: {},
  dataList,
  views,
  hooks,
  graphql
}

window.ReactFilteredlist

There is a global object on the window that has some useful functions. It's in its early development so it's sparse.

PropertyTypeDefaultPossible ValuesDescription
changeViewfunctionundefined(viewId)Passing this fn a view id, ie. apps, will behave the same as if you clicked on a tab in the views section.
resetFiltersfunctionundefined()Calling this runs a reset filter command
runFilterChangefunctionundefined({id, view, value})Calling this with a valid filter object will run that filter query. ie. window.ReactFilteredlist.runFilterChange({id: 'isActive', view: 'apps', value: 'true'})
stateobject{}{}This will always be the up-to-date state of the internal store. It is closesly connected to onStateUpdate. When onStateUpdate run, that's when the state property is populated.

Datalist

Some basic properties for the datalist. Most of the datalist props are controlled by the view, specifically. These properties apply across views. Honestly, these should really be reprogrammed to exist in the index.js file or vice-versa.

PropertyTypeDefaultPossible ValuesDescription
heightstringundefined'100%','200px'Takes a stringified css height value with units. Controls the overall height of the filteredlist component.
paginationBottomPositionstring'''36px','5%'Takes a stringified css value with units. Controls where near the bottom pagination controls sit.

Example

export default {
  height: '600px',
  paginationBottomPosition: '36px',
}

Views

Views are higher level filters & datalist pairs that run independent of eachother. They are rendered as tabs above the filters sidebar when more than one view is present. Essentially they are sub instances of the entire component within the component.

PropertyTypeDefaultPossible ValuesDescription
idstring''''The UNIQUE id of the view.
labelstring''''The display name for the view. Used by the tabs.
enableRowChecksbooleanfalsetrue,falseThis switch shows the row checks (thus enabling the checked items queue functionality) on the built in 'display' and 'text' displayTypes.
writeQueryStringToURLbooleanfalsetrue,falseThis switch controls if the filter query object can be written to the url for re-running the current state on page reload or share.
displayTypestring'''text','display', 'custom'Controls what to render on each of the datalist line item rows. Types: text simple line item, display [image & details line item. Expects an array of image objects to exist. images:{src: 'http://fillmurray.com/200/300',caption: "Bill Murray"}, or custom Provide a React component to the customDisplayTypeComponent prop below and it will receive the row item in its props. A note on custom display types: If you want your custom item to work with the grid, have it return an <li>, and use <span> inside it for cells. Whatever the direct wrapper of the <span> is ie. <li><a className="dl__listGridContainer"><span></span><span></span><span></span></a></li>, add the class dl__listGridContainer to it. It will become display:grid and it'll match the header row in behavior.
highlightSearchTermInTextBooleanfalsytrue/falseWhen set to true, this will take the cell text and add html <mark> tags around the search term in the queryObject (in the search bar). Right now this only works on the text displayType
customDisplayTypeComponentReact componentundefinedundefined, React componentSee the displayType property description for why this is used.
customContentPlaceholderReact component''''Used for displaying a content placeholder component instead of a loading gif while the user waits for item data to load and populate the rows.
customContentPlaceholderAmountintundefinedundefined,intSets the number of content placeholder rows to render while loading data.
enableGalleryLightboxbooleanfalsetrue,falseControls showing lightbox of the row image in the built-in display component when the user clicks the image.
showTabsHeaderbooleanfalsetrue,falseEnables the container for the view tabs.
showTabsbooleanfalsetrue,falseTurn on and off displaying the view tabs. You need this to click to more than one view. You can still get to a view via the url query string (?view=myotherview), but there will be no ui to switch back-and-forth.
showListHeaderbooleanfalsetrue,falseTurns on and off the datalist items column header. The header is good for text row views, but not applicable when using display components. This turns it off.
showSearchbooleanfalsetrue,falseForce hide the search component, even if it was provided as a special filter group(see filter groups below).
enableListSortbooleanfalsetrue,falseSwitch the data list header click column name to sort behavior.
showListSettingsbooleanfalsetrue,falseShows/hides a list properties checkbox interface for showing and hiding datalist columns. It sits in the top right corner of the datalist.
persistListSettingsbooleanfalsetrue,falseThis is used to set whether or not the user list settings options (what columns to show/hide) are persisted on reload. If true, the selected settings are stored in localstorage.
showResetFiltersButtonbooleanfalsetrue,falseEnables the reset filters link at the bottom of the filters sidebar UI.
showSaveFiltersInterfacebooleanfalsetrue,falseEnables the user saved filterset interface. If set to false it will not show up even if you have the filterset filter group imported in your configuration. (See the filter groups documentation for details.)
infoDisplaySettingsobjectundefinedundefined,{}Container for the info display strip located at the top of the filters sidebar ui, just below the view tabs. It contains the share link icon and any other icons you want to pass in.
infoDisplaySettings.showIconStripbooleanfalsetrue,falseTurn on and off the display of the icon strip.
infoDisplaySettings.showShareLinkbooleanfalsetrue,falseEnables a prebuilt share link in the icon strip that will copy to clipboard the current url and any query string in it.
infoDisplaySettings.showPaginationDatabooleanfalsetrue,falseShow data about the current page, total number of items, and loading status in the info bar.
infoDisplaySettings.iconComponentsarrayundefinedundefined,React componentAccepts an array of React components to create icons for displaying in the info/icon bar. The component will receive the entire config and the selectedView data in its props. Useful for custom actions on the dataset.
infoDisplaySettings.exportsobjectundefinedundefined, {}Container for the export feature settings accessed when showExport is true.
infoDisplaySettings.exports.apiUrlstringundefinedundefined, 'url'If a url is passed here, then the ajax call will use this url instead of the one set in the view's api settings. Useful for rest requests.
infoDisplaySettings.exports.ComponentReact Componentundefinedundefined, If a component is passed here, the internal modal will display this component over the built in internal export interface. The component is passed exportsSettings, selectedView, parentProps to its props. Important to note that the parent props has the modal in it as well as the action to controlModal. If you trigger controlModal({show: false}), you will close the modal. Useful for on success events.
filterGroupsarrayundefinedundefined,FilterGroupAn array of Filter Group object. See filter groups documentation for details on their contents.
itemIdPropstring''''The property containing the item id in the datalist item being rendered.
listEntityTypes[]undefinedundefined,[]LEGACY. Most likely not used anymore. @todo this one.
renderTostringundefinedundefined,'store''store' is the default. In the future we could render html, or to Meteor sessions, or anywhere else.
apiobjectundefinedundefined,{}Container for api settings used to make xhr requests
api.typestringundefined'graphql','rest'Request type to use. LEGACY: Everything is treated as rest and handled in the before XHR hook. @todo remove
api.urlstringundefined''The endpoint url used to make requests for data.
api.methodstringundefined'POST','GET'Request type. Usually POST.
api.xhrProxyfunctionundefinedundefined, functionIf not falsy, this get called instead of the filtered-list's internal xhr request library. The entire body of the request and the api options are passed through this function, you can make your xhr call, then use the callback to return your data. NOTE: This is the primary data entrypoint. The other entrypoint is the pushDispatch hook that allows pushing into the internal store.
api.tokenstring''undefined,''provide a token to pass to the authorization headers on the xhr request. If falsy the filtered-list will make untokened requests.
api.onTokenNeedsRefreshfunctionundefinedundefined, functionThis hook gets called if the token provided failed to pass the token validation check just before trying to make the running request. This is an opportunity to refresh the token then call the callback and continue making the request.
linkobjectundefinedundefined,objectContainer for the datalist row item link settings.
link.rowfunctionundefinedundefined, functionThis gets called when building the datalist item rows. The item is passed into the function and you need to return a link that the row item's anchor href will use when the user clicks a row item.
link.targetstring'''', '_blank'The row item link target settings. _blank opens the row item click in a new tab/window, '' opens it in place.
paginationPerPageOptionsArray or intundefinedundefined, int, int,intTHis array of ints populates the pagination bar's items per page dropdown, providing the possible values the user can choose from.
paginationTakeintundefinedundefined,intSets the number of items to fetch on each paginated request. This is page size.
noResultsMessagestring''''The message to display in the datalist container when the filter query returned no results.
usersSavedFiltersetsfunctionundefinedundefined, functionMust return a Promise containing a collection of items. This is how you populate the user saved filtersets select box options. In the hooks you can save to a database or local storage what the user saved then here you can retrieve it for option population.
propsarrayundefinedundefined,[]See the view props section below for an explanation of what goes in this array.
addonsarrayundefinedundefined, []Addons are pseudo filter types that can be added to the view outside of a a filter group. These exist in the internal store a filters and can store state. e.g. The search filter item is a built-in addon filter type.
searchButtonobjectundefinedundefined,objectContainer for search button themeing options.
searchButton.backgroundstring''''Accepts a hex string to set the background color of the search button.
searchButton.textstring''''Accepts a hex string to set the color of the search button text.

Example

import versionMetadata from '../filterGroups/version-metadata';
import versionContentType from '../filterGroups/version-contentType';
import versionRightsType from '../filterGroups/version-rightsType';
import userFiltersets from '../filterGroups/userFiltersets';
import sorting from '../filterGroups/sorting';

import search from '../filters/search';
import mapDictionary from '../maps';
import config from '../../config';
import { ENDPOINT_OFFERS } from '../../../config';

import DisplayItem from '../components/DisplayItem';
import ContentPlaceholder from '../components/ContentPlaceholder';
import filterDefaults from '../../../defaults';
import ExportIcon from '../components/ExportIcon';//icon component

export default {
  id: 'buyer',
  label: 'Buyer',
  enableRowChecks: false,
  writeQueryStringToURL: true,
  displayType: 'custom',

  customDisplayTypeComponent: DisplayItem,
  customContentPlaceholder: ContentPlaceholder,
  customContentPlaceholderAmount: 20,

  enableGalleryLightbox: true,
  showTabsHeader: false,
  showTabs: false,
  showListHeader: false,
  showSearch: true,
  enableListSort: false,
  showListSettings: false,
  showResetFiltersButton: true,
  showSaveFiltersInterface: true,

  infoDisplaySettings: {
    showIconStrip: true,
    showShareLink: true,
    showPaginationData: true,
    iconComponents: [ExportIcon]
  },
  filterGroups: [versionMetadata, sorting, userFiltersets],//versionRightsType,
  filterDefaults,
  itemIdProp: 'entityUUID',
  listEntityTypes: ['olyplat-entity-catalog'],
  renderTo: 'store',
  api: {
    type: 'rest',
    url: ENDPOINT_OFFERS,
    method: 'POST',
    xhrProxy: ({ uri, body }, cb) => {
        axios(uri, body)
          .then(res => {
            b(null, res, res);
          })
          .catch(err => {
            cb(err, null, null);
          });
    },
    token: (() => localStorage.getItem('id_token'))(),
    onTokenNeedsRefresh: cb => {cb();}
  },
  paginationTake: 25,
  link: {
    row: item => `https://mysite.com/item/${item.externalId}`,
    target: ''//use '' or '_blank'
  },
  noResultsMessage: "No items found",
  usersSavedFiltersets: () => new Promise((resolve, reject) => {
    //Do some stuff with the data, like storing it in your api, then resolve the promise.
  }),//returns a promise .
  props: [
   //See the view props object below for the contents of this array.
   // There should be one props object for each column displayed
  ],
  addons: [
    search
    // Use a filter object here
  ],
  searchButton: {
    background: '#4db3d7',
    text: '#fff'
  }
};

View Props

These are props objects that configure how default row text components display data.

Available item properties to the row. Also controls which props are visible by default or which are configurable in the column settings

PropertyTypeDefaultPossible ValuesDescription
keystring''''The key/property name of the property to display from the item being rendered as a row. This is the column data essentially.
labelstring''''The column name.
mapToobjectfalsyfalsy, {}Takes an object that it will use as a map to map item property names from one key to another. If the custom component you're using to render rows requires a certain schema and your item has a different schema, you can map property to property here.
hasCopybooleanfalsetrue,falseSwitch on the "copy to clipboard" icon/feature for the particular cell data.
isDatebooleanfalsetrue,falseIf you're passing in a date, switching this will convert the date timestamp to a human readable date.
isImagebooleanfalsetrue,falseUse this to tell the component we need to render the value as an image. This is useful for rendering a logo or user profile image in the cell.
fallbackImageSrcstring''image.extUsed in conjunction with the isImage prop. Ensures that a fallback is rendered if the previous image src is invalid.
isSortablebooleanfalsetrue,falseSwitch whether or not to allow the user to be able to sort this property from the list header column name interface.
widthstring'''11px', '100%'A stringified css value to determine the column width on the default text.
displaybooleanfalsetrue,falseLets the datalist know that it should display that column on load. If it's false, it will not dipslay on load but will still be available to the column settings interface.
beforefunctionA hook to transform the value (mostly for mapping) before rendering to the screen. If not using it, please set it like this until a default can be built in: before :(val,item)=>val @todo add default function check
lightboxImagesfunction({}, [{}])(item, items)A hook to send an array of images for react-images lightbox configuration. The function takes an initial image, then an array of images as its params. Please see react-images for configuration settings

Example

{
  key:'createdDate',
  label:'Created',
  mapTo : {"cardToOffer":"createdDate", "someProp":"alias"},
  hasCopy:false,
  isDate: true,
  isSortable : true,
  width:'12%',
  display: true,
  before :(val,item)=>val,
  lightboxImages: (item, items) => {}
}

Filter Groups

Filter groups are objects that have group configuration properties and a collection of filters. Take note of the 'filterset' id option. If 'filterset' is the filter group's id, then a user save filters group is renders that provides an interface for allowin the user to create, list, and delete saved filtersets.

PropertyTypeDefaultPossible ValuesDescription
idstring'''', 'filterset'The UNIQUE id of the group of filters. See filtergroup description above about the 'filterset' id behavior.
labelstring''NAThe display label that will be shown to the user next to the chevron open/close icon.
defaultOpenbooleanfalsetrue,falseWhen true, the filter group accordian will be open by default, showing all the filters. False means the group renders closed and the user has to click the checron to reveal the filters in the group accordian.
accordianobject{}NAOPtions for the themeing the filter group accordian display.
accordian.colorobject{}NAContainer object for the color themeing options.
accordian.color.backgroundstringundefinedNAAccepts a hexadecimal color string. Controls the accordian filter group title bar background color.
accordian.color.textstringundefinedNAAccepts a hexadecimal color string. Controls the accordian filter group title bar text & chevron background color.
filtersarray[]NATakes an array of filter objects to render inside it's accordian. See filters description below.

Examples

Filter group object

import sortCreatedDate from "../filters/sort-createdDate";

export default {
    id:'sorting',
    label : 'Sort by',
    defaultOpen: false,
    accordian:{ 
        color:{
            background: 'transparent',
            text:'#98999a'
        }
    },
    filters:[ sortCreatedDate ]
};

Special user filterset group

export default {
    id:'filterset',// This exact id is necesary to render the user save filterset interface as a group.
    label : 'Filters',
    defaultOpen: true,
    accordian:{ 
        color:{
            background: 'transparent',
            text:'#98999a'
        }
    },
    filters:[]
};

Filters

Used to take action on the dataset. Primary items used in building a query object that gets passed to the hooks and is used for writing the query string to the url. The id key becomes the property key in the queryObject.

PropertyTypeDefaultPossible ValuesDescription
idstring''NAThe id of the filter. Must be UNIQUE.
typestring'select''select', 'autocomplete', 'range', 'checkbox', 'radio', 'search', 'sort'This determines what type of filter item will be rendered. Special NOTE: Search type is a special filter that will render a search box where anything input will be passed as the value of a search filter property on the final object. The sort type is also special. It enables a sort toggle & request for the specified id/prop property. Also of note, the select and autocomplete type options.getOptions function needs to return a Promise. The rest just return the data they need.
propstring''NAEssentially the same as id. Just match this to the id until the api changes, then we'll handle that by default.
labelstring''NAThe filter item's Label property. THis displays to the user above the filter item.
valuearray/null/undefinednull{},{},{}Use this to set a default value. Value must be an array of objects (matching options), null or undefined to be excluded. (Filters recognize boolean true/false. An collection matching the select filter type can be passed to pre-populate the value.
placeholderstring''placeholderThe filter item's input placeholder property.
multibooleanfalsetrue,falseFor select filter types, this allows the select to be a multi select when set to true
fixedKeystring | prop1 | For property-search filter types, this allows the the filter to search on a fixed property and removes the select component
optionsobject{}{},falsyFor 'select' & 'checkbox' type only: The select type filter item's options handling. This takes care of property matching items so they can fill the value of the options element.
options.keystring''NAThis is the select box options item's key(property) to use for the option element's value property.
options.valuestring''NAThis is the select box options item's Label/Text to use in the option item's display.
options.getOptionsfunction/null/undefinedPromise, returnNAThis function must return a promise if using it for a select box and a collection if using it for a checkbox or range. It should return a collection to populate the select item's options. The items should have the properties specified in the key/value mapping above.
rangeobject{}{},falsyFor 'range' type only: Range type settings and defualts.
range.startUNIX timestampnullUNIX timestamp, nullSets the start time value for the range calendar in seconds.
range.endUNIX timestampnullUNIX timestamp, nullSets the end time value for the range calendar in seconds.

Examples

Select filter type

export default {
  id: 'countries',
  type:'select',
  prop: 'countries',
  label: 'Countries',
  value:null,
  multiple : true,
  options : {
      key : 'myPropId',
      value : 'myPropValue',
      getOptions : new Promise((resolve,reject)=>{
        resolve([
          {myPropId : 1, myPropValue: "Canada"},
          {myPropId : 2, myPropValue: "United States"},
          {myPropId : 3, myPropValue: "Mexico"}
        ]);
      })
  },
};

Autocomplete filter type

export default {
    id: 'tags',
    type: 'autocomplete',
    prop: 'tags',
    label: 'Tags',
    value: null,
    placeholder: 'Search for tags',
    options: {
        key: 'id',
        value: 'label',
        // Must return a promise containing a collection
        getOptions: new Promise((resolve,reject)=>{
            resolve([
                  {myPropId : 1, myPropValue: "Canada"},
                  {myPropId : 2, myPropValue: "United States"},
                  {myPropId : 3, myPropValue: "Mexico"}
            ]);
        })
    }
};

Property Search filter type

This filter is used for doing an "OR" search across a certain property. ie. search for a list of email addresses across the 'email' field on an entity.

When the options object is not being used to provide defaults for the select box, then the select box is automatically populated with all the properties listed in the props array for the selected view.

export default {
  id: "propertySearch",
  type: 'property-search',
  prop: "propertySearch",
  label: 'Property Search',
<<<<<<< HEAD
  placeholder: 'Placeholder',
=======
>>>>>>> origin/master
  fixedKey: 'property',
  inputType: 'number | text | date | ...' // value corresponds to the html input types
  value: null
  // options: {
    // key: 'id',
    // value: 'name'

    // Must return a promise containing a collection
    // Optional getOptions. If falsy, the component will get properties from the selectedView props
    // getOptions: () => Promise.resolve([
    //   {id: 0, name: 'entityUUID'},
    //   {id: 1, name: 'email'},
    //   {id: 2, name: 'name'},
    //   {id: 3, name: 'olyId'}
    // ])
  // }
};

Range filter type

export default {
    id: 'dateAvailable',
    type:'range',
    prop: 'dateAvailable',
    label: 'Dates Available',
    range:{
        start: 1520355600000 || null,
        end: 1520355600000 || null,
    }
};

Checkbox filter type

export default {
    id: filterKey,
    type:'checkbox',
    prop: filterKey,
    label: 'Checkbox Example', 
    value:null,
    multiple : true,
    options : {
        key : 'externalId',
        value : 'entityValue',
        getOptions : ()=>[
            {externalId:'true',entityValue:'Exclusive'},
            {externalId:'false',entityValue:'Non-Exclusive'}
        ]
    }
};

Radio filter type

export default {
    id: "isActive",
    type:'radio',
    prop: "isActive",
    label: 'Active', 
    value:null,
    multiple : true,
    options : {
        key : 'id',
        value : 'label',
        getOptions : ()=>[
            {id:'true',label:'Yes'},
            {id:'false',label:'No'}
        ]
    }
};

Search filter type

export default {
    id: 'search',
    type:'search',
    prop: 'search',
    label: 'Search',
    value:null,
};

Sort filter type

export default {
    id: filterKey,
    type:'sort',
    prop: filterKey,
    label: '',
    value:null
};

Hooks

The hooks are powerful. At different points in time throughout the lifecycle of the filteredlist component and on different actions the hooks are triggered. USe them to trigger actions in the parent app or to mutate data before sending requests to your apis. All hooks are just functions that get passed certain parameters and sometimes expect a response.

PropertyTypeReturn schemaParametersDescription
beforeXHRfunction{data, xhrOptions}(data, xhrOptions, requestData, requestType)Hook gets called just before the xhr request. It passes through the entire xhr params & the request body data raw. requestType will be undefined for primary requests, but can return a value of 'export' for when an export request is being generated. This allows specific export request handling inside the hook.
onXHRSuccessfunctionresolve({Items:[{}],total:1}),reject("some error message")(body,resolve,reject)Hook gets called when the xhr request returns successfully. A Promise is passed in the argument, it must be resolved. It's here that you can mutate data received from the api, then return wither an error message or an object of Items and the total.
onXHRErrorfunctionresolve({Items:[{}],total:1}),reject("some error message")(err, body,resolve,reject)Hook gets called when the xhr request kicks back an error
onCheckfunctionitem({item,workspaceItems})Hook for picking up check events. Note: You have access to all items currently in the workspace, but you must only return the item being mutated. Warning: a select all command will run this hook once for each item as it builds the workspaceItems list
onUnCheckfunctionNA({item,workspaceItems})Hook for picking up check events. Note: You have access to all items currently in the workspace, but you must only return the item being mutated. Warning: a select all command will run this hook once for each item as it empties the workspaceItems list
onStateUpdatefunctionNA(state, actionType, action)Hook gets called whenever the main application state gets updated. Useful for getting the filters' current queryObject, queryString or the action type. Pagination can also be read here as well as the current Selected View. THis is the ideal place to tie in Google Analytics from your parent app. You can use the actionType argument to determine what took place for your custom events.
onInitfunctionNA(app)Hook used to know when the app is initialized. If a fn is returned a callback is made accessible. If that callback is called(it has to be) then whatever data (an object) is passed to it will be made avialable in the preferences branch of the internal store on bootstrap. ie. onInit=(app)=>cb=>{cb({someDataForPrefs})}}
onSaveFiltersetfunctionNA({name,queryString,queryObject})Hook gets called when the user opted to save their filter set.
onDeleteFiltersetfunctionNA({name,filterset})Hook gets called when the user opted to delete their saved their filter set
onRowClickfunctiontrue,falsy(e, rowPath)Hook used to override the default row click event of a TextItem component. Return values of 'true' or 'falsy' enables this hook to break or continue the default TextItem onclick event respectively.
pushDispatchfunction({Items: {},count: 1})NASee the note below on the push dispatcher.
doFilterChangefunctioncallbackcb({id: 'isActive', view: 'users', value: 'false'})Exposes a callback function that when called passed a filterChange object it will run that filter change request. Good for programmatically triggering filter changes from the parent application. A filterChange object accepts 3 properties in the object, id(the id of the filter), view(the id of the current selected view), and value(the value to run OR 'null' to clear the filter)
doSortfunctioncallback()cb('createdAt', 'ASC');Because there is no easy to way refresh the last filter run(requests are memoized) it's convenient to have a sort hook. A callback function is exposed so you can programmatically trigger sort changes to refresh the current dataset. Use ASC or DESC as second argument values. If omitted DESC is the default value.

Push dispatch hook

This is a special "hook" used to push data structures directly to the internal Redux store. When the puser callback is triggered an internal dispatch is run. This is an experimental feature for connecting websocket data to the fitleredlist. See below example for some boilerplate code using Rxjs subscriptions.

Example

let pusher = () => { };

export default cb => {
  pusher = cb;
}

window.Oly.$tream
  .subscribe(data => {
    if (data.hasOwnProperty('data') && data.data.offers) {
      console.log('PUSHER', data.data.offers);
      pusher({
        Items: data.data.offers.items,
        count: data.data.offers.total
      })
    }
  });

Complete Example

Putting it all together: Complete configuration object example

Does not contain the imports, just the final structure example. It's wise to split this up into folders using ES6 imports and exports, for manageability.

Example suggested folder structure

filteredlistConfig
  index.js
  dataList.js
  /_utils
    index.js
  /components
    index.js
    DisplayComponent.js
  /filterGroups
    index.js
    sorting.js
    datesFiltergroup.js
  /filters
    index.js
    createdDate.js
    search.js
    genres.js
  /hooks
    index.js
    beforeXHR.js
    ...etc
  /views
    index.js
    primary.js
    secondary.js
  

Example complete configuration object

  export default {
    id: 'main',
    selector: '',
    defaultView: 'buyer',
    writeQueryStringToURL: true,
    runQueryStringURLOnRender: true,
    showFilters: true,
    filtersLabel: '',
    pinPagination: true,
    notify: (message, type, position) => { console.log(message, type, position); },
    header: {
      title: ''
    },
    footer: {},
    dataList:{
      height: undefined,
      paginationBottomPosition: '36px'
    },
    views: [
      {
        id: 'buyer',
        label: 'Buyer',
        enableRowChecks: false,
        writeQueryStringToURL: true,
        displayType: 'text',

        customDisplayTypeComponent: false,
        customContentPlaceholder: false,
        customContentPlaceholderAmount: 20,

        enableGalleryLightbox: true,
        showTabsHeader: false,
        showTabs: true,
        showListHeader: true,
        showSearch: true,
        enableListSort: true,
        showListSettings: true,
        showResetFiltersButton: true,
        showSaveFiltersInterface: true,

        infoDisplaySettings: {
          showIconStrip: true,
          showShareLink: true,
          showPaginationData: true,
          iconComponents: []
        },
        filterGroups: [
          {
            id:'sorting',
            label : 'Sort by',
            defaultOpen: false,
            accordian:{ 
                color:{
                    background: 'transparent',
                    text:'#98999a'
                }
            },
            filters:[ 
              {
                id: "sort-createdDate",
                type:'sort',
                prop: 'sort-createdDate',
                label: '',
                value:null
              } 
            ]
          }
        ],
        filterDefaults:[],
        itemIdProp: 'entityUUID',
        listEntityTypes: ['olyplat-entity-catalog'],
        renderTo: 'store',
        api: {
          type: 'graphql',
          url: "http://localhost",
          method: 'POST',
          xhrProxy: ({ uri, body }, cb) => {
              cb();
          },
          token: (() => localStorage.getItem('id_token'))(),
          onTokenNeedsRefresh: cb => {cb();}
        },
        paginationTake: 25,
        link: {
          row: item => `http://localhost:8000/item/${item.externalId}`,
          target: ''//use '' or '_blank'
        },
        noResultsMessage: "No items found",
        usersSavedFiltersets: () => new Promise((resolve, reject) => {
          resolve();
        }),
        props: [ 
          {
            key:'image',
            label:'Image',
            mapTo : {},
            hasCopy:false,
            isDate: false,
            isSortable : true,
            width:'33%',
            display: true,
            before :(val,item)=>val
          },
          {
            key:'entityUUID',
            label:'Id',
            mapTo : {},
            hasCopy:false,
            isDate: false,
            isSortable : true,
            width:'33%',
            display: true,
            before :(val,item)=>val
          },{
            key:'title',
            label:'Title',
            mapTo : {},
            hasCopy:false,
            isDate: false,
            isSortable : true,
            width:'33%',
            display: true,
            before :(val,item)=>val
          },
        ],
        addons: [{
          id: 'search',
          type:'search',
          prop: 'search',
          label: 'Search',
          value:null,
        }],
        searchButton: {
          background: '#4db3d7',
          text: '#fff'
        }
      }
    ],
    hooks: {
      beforeXHR: (data, xhrOptions, requestData) => {return {data, xhrOptions}},
      onXHRSuccess: (body,resolve,reject)=> { resolve( {
        Items: [
          {
            entityUUID: '0234',
            title: "Item 1",
            image: 'http://fillmurray.com/200/300'
          },
          {
            entityUUID: '023s4',
            title: "Item 2",
            image: 'http://fillmurray.com/200/300'
          },{
            entityUUID: '02g34',
            title: "Item 3",
            image: 'http://fillmurray.com/200/300'
          },
          {
            entityUUID: '02jh34',
            title: "Item 4",
            image: 'http://fillmurray.com/200/300'
          },
          {
            entityUUID: '023r4',
            title: "Item 5",
            image: 'http://fillmurray.com/200/300'
          }
      ],
        total: 5
      });
      },
      onXHRFail: (err,body)=>body,
      onCheck: ({item,workspaceItems})=>item,
      onUnCheck: ({item,workspaceItems})=>item,
      onStateUpdate: state => {},
      onRowClick: (e, rowPath) => true || falsy,
      onInit: app=>{},
      onSaveFilterset: ({name,queryString,queryObject})=>{},
      onDeleteFilterset: ({name,filterset})=>{},
      // pushDispatch: cb => { cb(); }
    }
}

Troubleshooting

Because this is a react component library, you may find (after react@16) that you get a react ref error saying you could have multiple copies of react running. If that's the case, in your parent application's webpack.config.dev.js or webpack.config.prod.js file add aliases for both react and react-dom that point to the parent app's node_modules folder.

alias: {
  react: path.resolve('./node_modules/react'),
  'react-dom': path.resolve('./node_modules/react-dom')
},

Also, in doing these aliases, you may need to allow webpack to use scope outside your src folder. If you see ModuleScopePlugin in your webpack config file (Ejected Create React Apps), then just remove that plugin. See this issue for more info: https://stackoverflow.com/questions/44114436/the-create-react-app-imports-restriction-outside-of-src-directory

17.0.2

5 years ago

17.0.1

5 years ago

17.0.0

5 years ago

16.12.16

5 years ago

16.12.15

5 years ago

16.12.14

5 years ago

16.12.13

5 years ago

16.12.12

5 years ago

16.12.11

5 years ago

16.12.9

5 years ago

16.12.8

5 years ago

16.12.7

5 years ago

16.12.5

5 years ago

16.12.4

5 years ago

16.12.3

5 years ago

16.12.2

5 years ago

16.12.1

5 years ago

16.12.0

5 years ago

16.11.1

5 years ago

16.11.0

5 years ago

16.10.0

5 years ago

16.9.0

5 years ago

16.8.1

5 years ago

16.8.0

5 years ago

16.7.1

5 years ago

16.7.0

5 years ago

16.6.10

5 years ago

16.6.9

5 years ago

16.6.8

5 years ago

16.6.7

5 years ago

16.6.5

6 years ago

16.6.4

6 years ago

16.6.2

6 years ago

16.6.1

6 years ago

16.6.0

6 years ago

16.4.0

6 years ago

16.3.12

6 years ago

16.3.10

6 years ago

16.3.9

6 years ago

16.3.8

6 years ago

16.3.7

6 years ago

16.3.6

6 years ago

16.3.5

6 years ago

16.3.4

6 years ago

16.3.3

6 years ago

16.3.2

6 years ago

16.3.1

6 years ago

16.3.0

6 years ago

16.2.7

6 years ago

16.2.6

6 years ago

16.2.5

6 years ago

16.2.4

6 years ago

16.2.3

6 years ago

16.2.2

6 years ago

16.2.1

6 years ago

16.2.0

6 years ago

16.1.22

6 years ago

16.1.21

6 years ago

16.1.20

6 years ago

16.1.19

6 years ago

16.1.18

6 years ago

16.1.5

6 years ago

16.1.4

6 years ago

16.1.3

6 years ago

16.1.2

6 years ago

16.1.1

6 years ago

3.0.0

6 years ago

2.0.3

6 years ago

2.0.2

6 years ago

1.20.5

6 years ago

1.20.4

6 years ago

1.20.3

6 years ago

1.20.2

6 years ago

1.20.1

6 years ago

1.20.0

6 years ago

1.19.5

6 years ago

1.19.4

6 years ago

1.19.3

6 years ago

1.19.1

6 years ago

1.19.0

6 years ago

1.18.2

6 years ago

1.18.0

6 years ago

1.17.1

7 years ago

1.16.7

7 years ago

1.17.0

7 years ago

1.16.6

7 years ago

1.16.2

7 years ago

1.15.0

7 years ago

1.14.10

7 years ago

1.14.8

7 years ago

1.14.6

7 years ago

1.14.5

7 years ago

1.14.4

7 years ago

1.14.3

7 years ago

1.14.2

7 years ago

1.14.0

7 years ago

1.13.4

7 years ago

1.13.2

7 years ago

1.13.1

7 years ago

1.12.8

7 years ago

1.12.7

7 years ago

1.12.6

7 years ago

1.12.4

7 years ago

1.12.3

7 years ago

1.12.2

7 years ago

1.12.0

7 years ago

1.11.14

7 years ago

1.11.13

7 years ago

1.11.11

7 years ago

1.11.10

7 years ago

1.11.9

7 years ago

1.11.8

7 years ago

1.11.7

7 years ago

1.11.6

7 years ago

1.11.5

7 years ago

1.11.4

7 years ago

1.11.3

7 years ago

1.11.2

7 years ago

1.11.1

7 years ago

1.11.0

7 years ago

1.10.3

7 years ago

1.10.2

7 years ago

1.10.1

7 years ago

1.10.0

7 years ago

1.9.6

7 years ago

1.9.5

7 years ago

1.9.4

7 years ago

1.9.3

7 years ago

1.9.2

7 years ago

1.9.0

7 years ago

1.8.8

7 years ago

1.8.7

7 years ago

1.8.6

7 years ago

1.8.5

7 years ago

1.8.4

7 years ago

1.8.3

7 years ago

1.8.2

7 years ago

1.8.1

7 years ago

1.8.0

7 years ago

1.7.3

7 years ago

1.7.2

7 years ago

1.7.1

7 years ago

1.7.0

7 years ago

1.6.10

7 years ago

1.6.9

7 years ago

1.6.8

7 years ago

1.6.7

7 years ago

1.6.6

7 years ago

1.6.5

7 years ago

1.6.3

7 years ago

1.6.2

7 years ago

1.6.1

7 years ago

1.5.0

7 years ago

1.4.9

7 years ago

1.4.8

7 years ago

1.4.7

7 years ago

1.4.6

7 years ago

1.4.5

7 years ago

1.4.4

7 years ago

1.4.3

7 years ago

1.4.0

7 years ago

1.3.0

7 years ago

1.2.0

7 years ago

1.1.2

7 years ago

1.0.8

7 years ago

1.0.7

7 years ago

1.0.6

7 years ago

1.0.5

7 years ago

1.0.2

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago