How to refresh a List View in admin on rest
Asked Answered
S

7

7

I am trying to get a list to refresh after a custom action was successfully executed.

i used the saga from the admin on rest tutorial

function * actionApproveSuccess () {
  yield put(showNotification('Executed'))
  yield put(push('/comments')) 
  // does not refresh, because the route does not change
  // react-redux-router also has no refresh() method, like react-router has...
}

the other idea i had was to somehow trigger the refresh action of the list component, but i have no idea how to access that or how to hook that up to the ACTION_SUCCESS event.

Solidary answered 4/4, 2017 at 16:19 Comment(0)
T
6

There is no way to refresh a route via react router, and that's a known problem. Admin-on-rest's List component has its own refresh mechanism, but offers no API for it.

My advice would be to use a custom <List> component based on admin-on-rest's one. And if you find a way to expose the refresh action, feel free to open a PR on the aor repository!

Trona answered 6/4, 2017 at 11:45 Comment(0)
A
4

@Danila Smirnov's answer above shows this message when I use it now:

Deprecation warning: The preferred way to refresh the List view is to connect your custom button with redux and dispatch the refreshView action.

Clicking the refresh button itself wasn't working either nowadays.

Here's the tweaked version that I got working in mine.

Edit: Modified it a bit more to make it reusable.


RefreshListActions.js

import React, { Component } from 'react'
import FlatButton from 'material-ui/FlatButton'
import { CardActions } from 'material-ui/Card'
import NavigationRefresh from 'material-ui/svg-icons/navigation/refresh'
import { connect } from 'react-redux'
import { REFRESH_VIEW } from 'admin-on-rest/src/actions/uiActions'
import { refreshView as refreshViewAction } from 'admin-on-rest/src/actions/uiActions'

class MyRefresh extends Component {
    componentDidMount() {
        const { refreshInterval, refreshView } = this.props
        if (refreshInterval) {
            this.interval = setInterval(() => {
                refreshView()
            }, refreshInterval)
        }
    }

    componentWillUnmount() {
        clearInterval(this.interval)
    }

    render() {
        const { label, refreshView, icon } = this.props;
        return (
            <FlatButton
                primary
                label={label}
                onClick={refreshView}
                icon={icon}
            />
        );
    }
}

const RefreshButton = connect(null, { refreshView: refreshViewAction })(MyRefresh)

const RefreshListActions = ({ resource, filters, displayedFilters, filterValues, basePath, showFilter, refreshInterval }) => (
    <CardActions>
        {filters && React.cloneElement(filters, { resource, showFilter, displayedFilters, filterValues, context: 'button' }) }
        <RefreshButton primary label="Refresh" refreshInterval={refreshInterval} icon={<NavigationRefresh />} />
    </CardActions>
);

export default RefreshListActions

In my list that I want to refresh so often:

import RefreshListActions from './RefreshListActions'

export default (props) => (
    <List {...props}
        actions={<RefreshListActions refreshInterval="10000" />}
        >
        <Datagrid>
            ...
        </Datagrid>
    </List>
)
Acetous answered 5/10, 2017 at 2:32 Comment(1)
This is working. It is better if to created the button which has a drop down menu for auto update intervals, like disable, 10, 50, 100, etc. I see someone has similar idea in the other post, #44552457. but no luck to make it workBabby
F
3

Definitely hacky, but a work-around could be:

push('/comments/1') //any path to change the current route
push('/comments') //the path to refresh, which is now a new route
Formulaic answered 21/6, 2017 at 19:56 Comment(0)
T
2

using refreshView action via redux works well.

see example....

import { refreshView as refreshViewAction } from 'admin-on-rest';
import { connect } from 'react-redux'; 

class MyReactComponent extends Component {
  //... etc etc standard react stuff...

 doSomething() {
    // etc etc do smt then trigger refreshView like below  
    this.props.refreshView();
 }
 render() {
   return <div>etc etc your stuff</div>
 }
}

export default connect(undefined, { refreshView: refreshViewAction })(
  MyReactComponent
);
Tradespeople answered 15/11, 2017 at 19:38 Comment(2)
This worked for me to refresh a list after a custom action has executed. Thanks a bunch!Biff
Awesome, but how do you do if you don't want to dispatch and just listen to refresh so I can fix UI not build with react-admin components?Plumbism
M
1

I've solve this task with small hack via Actions panel. I'm sure it is not correct solution, but in some situations it can help:

class RefreshButton extends FlatButton {
  componentDidMount() {
    if (this.props.refreshInterval) {
      this.interval = setInterval(() => {
        this.props.refresh(new Event('refresh'))
      }, this.props.refreshInterval)
    }
  }

  componentWillUnmount() {
    clearInterval(this.interval)
  }
}

const StreamActions = ({ resource, filters, displayedFilters, filterValues, basePath, showFilter, refresh }) => (
  <CardActions>
    {filters && React.cloneElement(filters, { resource, showFilter, displayedFilters, filterValues, context: 'button' }) }
    <RefreshButton primary label="Refresh streams" onClick={refresh} refreshInterval={15000} refresh={refresh} icon={<NavigationRefresh />} />
  </CardActions>
);

export default class StreamsListPage extends Component {
  render() {
    return (
      <List
        {...this.props}
        perPage={20}
        actions={<StreamActions />}
        filter={{ active: true }}
        title='Active Streams'>
        <StreamsList />
      </List>
    )
  }
}
Madly answered 16/8, 2017 at 16:30 Comment(2)
Just tried it and it's showing an error and this notice: "Deprecation warning: The preferred way to refresh the List view is to connect your custom button with redux and dispatch the refreshView action."Acetous
It was an old version of package. There is no need this trick in modern appMadly
U
1

The push is just a redirect for AOR which did not seem to work for me either. What guleryuz posted was on the right track for me.. Here's what I did building on his example:

// Import Statement
import { refreshView as refreshViewAction } from 'admin-on-rest';

class RemoveButton extends Component {
handleClick = () => {
    const { refreshView, record, showNotification } = this.props;
    fetch(`http://localhost:33333/api/v1/batch/stage/${record.id}`, { method: 'DELETE' })
        .then(() => {
            showNotification('Removed domain from current stage');
            refreshView();
        })
        .catch((e) => {
            console.error(e);
            showNotification('Error: could not find domain');
        });
}

 render() {
    return <FlatButton secondary label="Delete" icon={<DeleteIcon />}onClick={this.handleClick} />;
 }
}

These bits are important as well:

RemoveButton.propTypes = {
record: PropTypes.object,
showNotification: PropTypes.func,
refreshView: PropTypes.func,
};

export default connect(null, {
showNotification: showNotificationAction,
refreshView: refreshViewAction,
})(RemoveButton);

So the way this works is it uses AOR's refreshViewAction as a prop function. This uses the underlying call to populate the data grid for me which is GET_LIST. This may not apply to your specific use case. Let me know if you have any questions.

Unworthy answered 12/12, 2017 at 19:23 Comment(0)
M
0

Pim Schaaf's solution worked like a charm for me, Mine looks a bit different

yield put(push('/comments/-1')); // This refreshes the data
yield put(showNotification('')); // Hide error 
Mead answered 30/5, 2018 at 12:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.