Admin on Rest onClick being called on render and not on click - admin-on-rest

The issue I am having is I have a button:
const LogActions = ({ resource, filters, displayedFilters, filterValues, basePath, showFilter, refresh, record }) => (
<CardActions style={cardActionStyle}>
<RaisedButton primary label="Cancel" onClick={HandleClick(record["id"])} />/>
</CardActions>
);
This button is used in a List like so:
export const LogList = (props) => (
<List {...props} perPage={100} title="Logs and Reports" filters={< FileFilter/>}>
<Datagrid>
<TextField source="inputfile" label="Input File" />
<TextField source="cycle" label="Cycle" />
<TextField source="job" label="Job" />
<TextField source="name" label="File Name" />
<ShowButton/>
<LogActions/>
</Datagrid>
</List>
);
This is the HandleClick:
const HandleClick = (id) => {
fetch(`controller_service/archivedfiles/${id}`, { method: 'GET', body:{} })
.then(() => {
// do stuff
})
.catch((e) => {
console.error(e);
//error
});
}
Okay so my problem is that whenever I go to this page, it will create the datagrid, but while the button is being rendered it calls HandleClick which then fetches that data before I even click on the button, and when I click on the button nothing happens. Can someone explain what I am doing wrong?

As wesley6j said, the function gets called when you assign it with parameters.
A way to avoid this is to use .bind(this,params) or wrap your HandleClick in another function like this:
onClick={() => HandleClick(record["id"])}

Related

react hook, validate Form with reduxForm

I Have external component managing my input Field and throws an error if no input is made.
On submit of form previously with class component along with reduxForm effect, this would throw an error of missing input, am wondering how to achieve this with hooks since submission passes whether i have input or Not.
import ConstructField from '../components.render';
const ActivitiesForm = () => {
const handleSubmit_ = () => {
console.log({ activityName });
};
const [activityName, setActivityName] = useState(null);
const handleInputName = (e) => setActivityName(e.target.value);
const { items } = useSelector((state) => ({
items: state.items,
}));
const { register, handleSubmit, errors, control } = useForm();
return (
<div>
<Form onSubmit={handleSubmit(handleSubmit_)} className='ui form'>
<Form.Group widths='equal'>
<Field
component={ConstructField('input')}
onChange={handleInputName}
label='Activity Name'
name='activityName'
placeholder='Activity Name'
validate={required}
/>
</Form.Group>
<br />
<Form.Group inline>
<Button.Group>
<Button primary>Save</Button>
<Button.Or />
<Button positive onClick={goBackButton}>
Go Back
</Button>
</Button.Group>
</Form.Group>
</Form>
</div>
);
};
const required = (value) => (value ? undefined : 'this field is required');
const activityform = reduxForm({
form: 'activityform',
enableReinitialize: true,
})(ActivitiesForm);
export default activityform;

React Native Stack Navigator passing props

I want to pass some props (value) to another page and I'm using stackNavigator
App.js:
import Insert from "./components/pages/Insert";
import ViewData from "./components/pages/ViewData";
const Stack = createStackNavigator();
NavigationContainer>
<Stack.Navigator headerMode={false}>
<Stack.Screen name="Insert Your data" component={Insert} />
<Stack.Screen name="ViewData" component={ViewData} />
</Stack.Navigator>
</NavigationContainer>
Insert.js
const Insert = ({ props, navigation: { navigate } }) => {
const [enteredName, setEnteredName] = useState();
const [enteredSurname, setEnteredSurname] = useState();
const sendValues = (enteredName, enteredSurname) => {
setEnteredName(enteredName);
setEnteredSurname(enteredSurname);
navigate("ViewData", {
name: enteredSurname,
surname: enteredSurname
});
};
...
<View>
<Button
title="Submit"
onPress={() => sendValues(enteredName, enteredSurname)}
/>
ViewData.js
const ViewData = ({props, navigation: { goBack } }) => {
let name = enteredName;
console.log(name); /// I always get undefined
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Here {name}</Text>
<Button onPress={() => goBack()} title="Edit Data" />
</View>
);
};
When I Submit I'm always getting undefined into the console.
For sure I'm mistaking somewhere.
Any idea?
Thanks!!
Refer to https://reactnavigation.org/docs/hello-react-navigation/#passing-additional-props
Use a render callback for the screen instead of specifying a component
prop:
<Stack.Screen name="Home">
{props => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
You can change like this
import Insert from "./components/pages/Insert";
import ViewData from "./components/pages/ViewData";
const Stack = createStackNavigator();
<NavigationContainer>
<Stack.Navigator headerMode={false}>
<Stack.Screen name="Insert Your data">
{props => (<Insert {...props} extraData={data}/>)}
<Stack.Screen name="ViewData" component={ViewData} />
</Stack.Navigator>
</NavigationContainer>
Reading your code it seems that you want to pass some params to the render component when navigate.
Refer to https://reactnavigation.org/docs/route-prop , the params from
navigation.navigate(routeName, params)
are passed to the screen render component as propriety of the route object. So in your case it should work:
let name = props.route.params.name;

How to change value of input in Admin on Rest from another component in Create form?

I've reduced this to a very simple case for ease of discussion. I have a simple create form with 1 field and 1 button. I would like the button to set the value of the TextInput to "Hello" without submitting the form. How is this possible in admin on rest? eg:
export const TestCreate = (props) => (
<Create title={<TestTitle />} {...props}>
<SimpleForm>
<TextInput source="title" />
<TitleSetterButton />
</SimpleForm>
</Create>
);
Been struggling with this for a while - it should be simple so hopefully there's an easy answer.
I was able to setup a Sample form using their example application
// in src/posts.js
import React from 'react';
import { List, Edit, Create, Datagrid, ReferenceField, TextField, EditButton, DisabledInput, LongTextInput, ReferenceInput, required, SelectInput, SimpleForm, TextInput } from 'admin-on-rest';
import FlatButton from 'material-ui/FlatButton';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" />
<ReferenceField label="User" source="userId" reference="users">
<TextField source="name" />
</ReferenceField>
<TextField source="title" />
<TextField source="body" />
<EditButton />
</Datagrid>
</List>
);
const PostTitle = ({ record }) => {
return <span>Post {record ? `"${record.title}"` : ''}</span>;
};
export class Testing extends React.Component {
render() {
return <input type="text" />
}
}
export class PostCreate extends React.Component {
componentDidMount() {
console.log(this)
}
constructor(props) {
super(props);
this.handleCustomClick = this.handleCustomClick.bind(this);
// this.fieldOptions = this.fieldOptions.bind(this);
}
handleCustomClick() {
this.fields.title.handleInputBlur("tarun lalwani");
this.fields.body.handleInputBlur("this is how you change it!");
}
render () {
let refOptions = {ref: (e) => {
if (e && e.constructor && e.props && e.props.name) {
this.fields = this.fields || {};
this.fields[e.props.name] = e;
}
}}
return (
<Edit title={<PostTitle />} {...this.props}>
<SimpleForm>
<DisabledInput source="id" />
<ReferenceInput label="User" source="userId" reference="users" validate={required}>
<SelectInput optionText="name" />
</ReferenceInput>
<TextInput source="title" options={refOptions}/>
<LongTextInput source="body" options={refOptions}/>
<FlatButton primary label="Set Value" onClick={this.handleCustomClick} />
</SimpleForm>
</Edit>
);
}
}
Before click of the button
After clicking Set Value
And then after clicking Save you can see the actual changed values get posted

How to dispatch an action that changes the state of a component from its parent component?

I'm trying to implement a modal dialog that asks if I'm sure if I want to delete or not an item in application. I've this components:
const Options = item => (
<OptionsMenu>
<MenuItem onClick={_ => {
console.log(`Deleting item ${JSON.stringify(item)}`)
}}>
<IconButton aria-label="Delete" color="accent">
<DeleteIcon />
</IconButton>
<Typography>
Eliminar
</Typography>
</MenuItem>
<DeleteDialog
item={item}
/>
</OptionsMenu>
)
And my dialog component is:
const DeleteDialog = props => (
<div>
<Button onClick={() => {
this.props.openDeleteDialog(this.props.item)
}}>Delete</Button>
<Dialog open={this.props.open} onRequestClose={this.props.cancelDeleteData}>
<DialogTitle>{"DELETE"}</DialogTitle>
<DialogContent>
<DialogContentText>
Are you sure you want to delete the item: {this.props.item.name}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.props.cancelDeleteData} color="primary">
Cancel
</Button>
<Button onClick={this.props.deleteData(this.props.item)} color="primary">
Delete
</Button>
</DialogActions>
</Dialog>
</div>
);
const mapStateToProps = state => ({
open: state.item.delete.open,
})
const mapDispatchToProps = dispatch => ({
...deleteDispatchesForScope(scopes.ITEM, dispatch)
})
What I want is to dispatch the openDeleteDialog action, that sets the open state to true, from the Options component in a way that I will allow me to reuse the modal Dialog in other components.
I'm using react-redux and material-ui v1 for this.
In order to have more reusable components, I would decouple the DeleteDialog from the OptionsMenu, and rely on a ParentComponent to pass down the props required for each child:
<ParentComponent>
<OptionsMenu>
<MenuItem onClick={this.props.openDeleteDialog}>Eliminar</MenuItem>
</OptionsMenu>
<DeleteDialog
open={this.props.isDeleteDialogOpen}
item={this.props.item}
onDelete={this.props.deleteData}
/>
</ParentComponent>

Admin on rest custom button

I would like to make a custom button that would be used to fetch. I want the button to be usable like this:
export const LogList = (props) => (
<List {...props} perPage={100} title="Logs and Reports" filters={< FileFilter/>}>
<Datagrid>
<TextField source="inputfile" label="Input File" />
<TextField source="cycle" label="Cycle" />
<TextField source="job" label="Job" />
<TextField source="name" label="File Name" />
<ShowButton/>
<JobCancel/>
</Datagrid>
</List>
);
Where is my button is <JobCancel/> up above (similar to how ShowButton is implemented). I want the button to fetch(controller_service/archivedfiles/${id}, { method: 'DELETE', body:{} }); on click.
Is something like this possible?
P.S. I am new to Admin on rest
You can also find an example for custom actions in the demo repository for reviews (accept, reject): https://github.com/marmelab/admin-on-rest-demo/tree/master/src/reviews
Misread your question. So am editing my answer.
I have custom button for my list view.
It's a straightforward Redux connected component.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import RaisedButton from 'material-ui/RaisedButton';
import { editorAssign as editorAssignAction} from '../customActions/EditorAssignActions'
import styles from '../styles/styles'
class EditorAssignButton extends Component {
constructor(props){
super(props);
this.state = { disabled: false };
}
handleClick = () => {
const { editorAssign, record } = this.props
editorAssign(record.id) //call the action
this.setState({
disabled: true
})
}
render() {
const editorAssignStyle = styles.editorAssignStyle;
return (<RaisedButton label='Add To Edit'
onClick={this.handleClick}
disabled={ this.state.disabled }
primary={true}
/>)
}
}
EditorAssignButton.propTypes = {
editorAssign: PropTypes.func,
record: PropTypes.object
}
export default connect(null, {
editorAssign: editorAssignAction
})(EditorAssignButton)
AOR has documentation on how to write custom actions and trigger side effects with Sagas.
https://marmelab.com/admin-on-rest/Actions.html
DELETE is an action available with AOR Rest so your requirement should be quite standard.
Here is the EditorAssign view. It is a straightforward list and datagrid component
import React from 'react';
import { ReferenceField,
ChipField,
SelectInput,
ReferenceInput,
TextField,
List,
Filter,
Datagrid} from 'admin-on-rest';
import AssignTaleEditToSelf from '../buttons/AssignTaleEditToSelf'
const EditorAssignView = (props) => {
return (
<List {...props} title="Fresh Tales" perPage={20} sort={{ field: 'id', order: 'ASC' }} filter={{"status": "NEW"}} filters={ <EditorFilter /> } >
<Datagrid >
<TextField source="id" label="id" style={{ textAlign: 'center'}} />
<TextField source="taleTitle" label="Title" />
<TextField source="taleText" label="Content" style={{maxWidth: '150px'}} />
<ReferenceField label="Writer" source="writer_id" reference="appUsers">
<ChipField source="name" />
</ReferenceField>
<AssignTaleEditToSelf label="Assign To Self" />
</CustomDatagrid>
</List>
)
}
}

Resources