72725

Admin-on-rest - how to sync other components with query filtered from List?

Question:

I want to implement this structure in the page:<br /> 1. Cards with summary (revenue, users, etc.)<br /> 2. Map from google maps<br /> 3. List element

Inside List element there is filtering. I am stuck how to user filter options when filtering list to represent filtered information in the map and cards.

As @trixn recommended I am using this structure:

// app.js <Admin restClient={jsonServerRestClient('http://jsonplaceholder.typicode.com')}> <Resource name="posts" list={MyCustomPostList} /* other views */ /> </Admin> // MyCustomPostList.js class MyCustomPostList extends React.Component { render() { const {myOwnProp, ...otherProps} = this.props; return ( <div> // render your own components here <AnyComponent myOwnProp={myOwnProp} /> <AGoogleMapsComponent /> // render the normal <List> component <List {...otherProps}> <Datagrid> <TextField source="id" /> <TextField source="title" /> <TextField source="body" /> </Datagrid> </List> </div> ); } }

Now I am failing to send required data to Maps and AnyComponent. So I either have to pass same data to Maps and AnyComponent or somehow synchornize filters that are being used in the List component.

How shall I achieve this?

Answer1:

<blockquote>

Thank you! I would know how to connect new actions. But I am lost how to connect to already used actions to pass Filter options to Maps and AnyComponent, so I could show relevant information there, which should update its state after Filters are being triggered in List component.

</blockquote>

You do not connect to actions. You dispatch them to alter the state of the redux store. It is important that you fully understand the concepts of redux otherwise it will be very hard for you to build this kind of custom app. To make sure data is only flowing from top to bottom components can only listen to changes of the store and not to actions.

So basically you have two options:

<strong>1. Create your own <List> component</strong>

Quoted from the admin-on-rest docs:

<blockquote>

Admin-on-rest was build with customization in mind. You can replace any admin-on-rest component with a component of your own, for instance to display a custom list layout, or a different edition form for a given resource.

</blockquote>

If you only want to display your additional elements in your list view you can wrap the <List> component instead of the <Resource> component. The <List> component receives the entities in a prop "data" and the filtered ids in a prop "ids". You can use that to display it in your own component. E.g. if you want to manage a list of locations and show a google map inside the list component:

<pre class="lang-js prettyprint-override">import React from 'react'; import { List } from 'admin-on-rest'; const LocationsList = props => ( // render your own components <MyGoogleMapsComponent data={this.props.data} ids={this.props.ids}> // render the admin-on-rest <List> component <List {...props}> // render the DataGrid </List> );

Then you can pass your custom list to the <Resource> component:

<Admin> <Resource name="locations" list={LocationList} /> </Admin>

When you filter your locations in the list the updated query will be passed to your <LocationList> and it will re-render with the new locations. But remember that this will only show your google map inside the list view of your admin page.

<strong>2. Connect your component to the redux store.</strong>

Do this only if you want your component, e.g. the google map, to be displayed outside of your list view. This one is much more advanced as you will need to learn a lot more about the internals of admin-on-rest. You will have to connect your custom component to the redux store. You can do that with the <a href="https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options" rel="nofollow">connect()</a> function from the react-redux package:

// in MyGoogleMapsComponent.js import React from 'react'; import { connect } from 'react-redux'; const LocationMap = ({locations}) => ( //render something based on the props ); const mapStateToProps = (state, props) => { // state.admin contains all the registered resources with their name as a key const locationsResource = state.admin.locations; // every resource has a "data" object with all entities mapped by id const allLocations = locationsResource.data; // every resource has a "list" object that has an array of ids of the currently filtered entities const filteredIDs = locationsResource.list.ids; return { locations: filteredIDs.map(id => allLocations[id]), }; }; // connect your component to the store export default connect(mapStateToProps)(LocationsList)

mapStateToProps is a function that takes the current state in your store and the props of your component and returns an object containing additional props to be passed to your component.

Also this approach uses internals of the implementation of the admin-on-rest components. Some of the props you'll need to use are not part of the api and could in the worst case suddenly change in which case your app may not work anymore if you update to a new version of admin-on-rest. So keep in mind you may need to update your implementation when breaking changes occur.

If you only want to access the filters itself, they are stored in every resource under yourResourceName.list.params.filter with the name of the filter as the key and the value as the value...

<strong>Hint:</strong> If you want to see, how data inside the store of an admin-on-rest app ist stored in a real life example install the <a href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd" rel="nofollow">Redux DevTools</a> for google chrome and open the <a href="https://marmelab.com/admin-on-rest-demo" rel="nofollow">admin-on-rest demo</a>. You can then open the inspection bar and there will be a new tab redux where you can see the contents of the redux store and all the actions that get dispatched when interacting with the app. This way you it will be much easier to understand how admin-on-rest works.

Answer2:

The List component exported by admin-on-rest is connected with redux and receive the filters from state. You should do the same. See the code of the List component, espcially the <a href="https://github.com/marmelab/admin-on-rest/blob/master/src/mui/list/List.js#L293" rel="nofollow">mapStateToProps</a> function:

The List component exported by admin-on-rest is connected with redux and receive the filters from state. You should do the same. See the code of the List component, espcially the <a href="https://github.com/marmelab/admin-on-rest/blob/master/src/mui/list/List.js#L293" rel="nofollow">mapStateToProps</a> function:

Something like:

// MyCustomPostList.js import { connect } from 'react-redux'; import { parse } from 'query-string'; class MyCustomPostList extends React.Component { render() { const { myOwnProp, query: { filter }, ...otherProps } = this.props; return ( <div> // render your own components here <AnyComponent filter={filter} myOwnProp={myOwnProp} /> <AGoogleMapsComponent filter={filter} /> // render the normal <List> component <List {...otherProps}> <Datagrid> <TextField source="id" /> <TextField source="title" /> <TextField source="body" /> </Datagrid> </List> </div> ); } } const getLocationSearch = props => props.location.search; const getQuery = createSelector( getLocationSearch, (locationSearch) => { const query = parse(locationSearch); if (query.filter && typeof query.filter === 'string') { query.filter = JSON.parse(query.filter); } return query; }, ); function mapStateToProps(state, props) { return { query: getQuery(props), }; } export default connect(mapStateToProps)(MyCustomPostList);

Recommend

  • Zend Framework 2 - Building a simple form with Validators
  • Combining many rectangles into fewer rectangles
  • Thrust filter by key value
  • C: Custom strlen() library function
  • Ncurses No Output
  • opengl window freezing during move/resize
  • p:fileDownload in p:dataTable does not work (just refreshes page) after performing search on the p:d
  • EntLib Way to Bind “Null” Value to Parameter
  • Why must we declare a variable name when adding a method to a struct in Golang?
  • JSR-330 support in Picocontainer : @Inject … @Named(\"xxx)
  • Python ImageIO Gif Set Delay Between Frames
  • Creating a DropDownList
  • Who propagate bugfixes across branches (corporate development)?
  • UIAlertController button function not working
  • Django model inheritance, filtering models
  • Android Google Maps API v2 start navigation
  • Does Mobilefirst provide a provision to access web services directly?
  • MS Access - How to change the linked table path by amend the table
  • Textfile Structure (tables)
  • Scrapy recursive link crawler
  • java.lang.NoClassDefFoundError: com.parse.Parse$Configuration$Builder on below Lollipop versions
  • Jenkins: How To Build multiple projects from a TFS repository?
  • Spring security and special characters
  • req.body is undefined - nodejs
  • Is possible to count alias result on mysql
  • Sending data from AppleScript to FileMaker records
  • retrieve vertices with no linked edge in arangodb
  • KeystoneJS: Relationships in Admin UI not updating
  • AngularJs get employee from factory
  • Codeigniter doesn't let me update entry, because some fields must be unique
  • Benchmarking RAM performance - UWP and C#
  • Load html files in TinyMce
  • using HTMLImports.whenReady not working in chrome
  • embed rChart in Markdown
  • Linking SubReports Without LinkChild/LinkMaster
  • Does armcc optimizes non-volatile variables with -O0?
  • How to get NHibernate ISession to cache entity not retrieved by primary key
  • How can I use `wmic` in a Windows PE script?
  • Unable to use reactive element in my shiny app
  • Python/Django TangoWithDjango Models and Databases