How to hide columns in Datagrid based on filters values - admin-on-rest

Can we dynamically show/hide the columns of a List Datagrid based on the filters values?
I do not see how we can do this. Thanks for any help on this.

This is not possible with the default ra-ui-materialui List component. You'll have to implement your own, using it as a starting point.
Feel free to open a feature request issue on the https://github.com/marmelab/react-admin repository describing the use case.

You can refer to this link for customizing your datagrid columns : https://github.com/fizix-io/ra-customizable-datagrid
OR,
you can make your list component as a stateful component, and implement your own Actions in the List component like a toggle button.
For Example:
class MoreDetails extends Component {
constructor() {
super();
this.state = {
showDetails: false
};
}
toggleDetails = () => {
const toggle = this.state.showDetails;
this.setState((prevState, props) => {
return {
showDetails: !toggle,
}
});
}
render() {
const { classes, ...props } = this.props;
const MyActions = ({ basePath, data, resource }) => (
<CardActions style={cardActionStyle}>
<Button
color="primary"
onClick={this.toggleDetails}
>Toggle Details</Button>
</CardActions>
);
return <List
actions={<MyActions />}
{...props} >
<Datagrid>
<TextField source="c1" label="Column1" />
<TextField source="c2" label="Column2" />
{this.state.showDetails ?
<TextField source="c3" label="Column3" /> : null }
<TextField source="c4" label="Column4" />
{this.state.showDetails ?
<TextField source="c5" label="Column5" /> : null }
</Datagrid>
</List>
}
}

Related

React-bootstrap (BS v3) - can not use a ref from an input

I’m using react-bootstrap, but with bootstrap v3, because that’s the bootstrap version my project currently uses.
Now, I just need to have a ref from an input. In the react-bootstrap docs, it says you should use formControl’s inputRef property like this:
<FormControl inputRef={ref => { this.input = ref; }} />
But currently, I’m using a function and react hooks to build my component, instead of classes.
So I just wrote my code this way:
let inputReferencia = useRef(null);
In onFocus event, I use this statement to select the content of the input:
inputReferencia.current.select();
And, finally, this is my input, as per react-bootstrap syntax:
<FormGroup>
<FieldGroup
id="referencia"
name="referencia"
value={formValues.referencia}
type="text"
label="Referencia"
onFocus={(e) => onDescripcionReferenciaInputFocus(e)}
onChange={(e) => onInputChange(e)}
inputRef={ref => { inputReferencia = ref; }} />
</FormGroup>
As React-bootstrap suggests, this is FieldGroup:
const FieldGroup = ({ id, label, help, ...props }) => {
return (
<FormGroup controlId={id} bsSize="small">
<ControlLabel>{label}</ControlLabel>
<FormControl {...props} />
{help && <HelpBlock>{help}</HelpBlock>}
</FormGroup>
);
}
But when I try to access the ref, as in
inputReferencia.current.select()
the current property is undefined.
Of course, if I check out the ref in Chrome debugger, it was definitely initialized with something:
Can somebody help me to solve this issue?
Many thanks for your help …
According to the docs you ought to use ref instead of inputRef. This is regardless of whether you are using Bootstrap V3 or Bootstrap V4 or any other version as React-bootstrap only uses their stylesheet.
In dealing with functional components and trying to access the child element's ref on the parent when the ref variable is declared on the parent, you can opt to use forwardRef
function App() {
let inputReferencia = useRef(null);
function onDescripcionReferenciaInputFocus(e) {
console.log(`inputReferencia`, inputReferencia);
}
return (
<Container>
<FormGroup>
<FieldGroup
id="referencia"
name="referencia"
value={formValues.referencia}
type="text"
label="Referencia"
onFocus={(e) => onDescripcionReferenciaInputFocus(e)}
onChange={(e) => onInputChange(e)}
ref={inputReferencia}
/>
</FormGroup>
</Container>
);
}
const FieldGroup = React.forwardRef(({ id, label, help, ...props }, ref) => {
return (
<FormGroup controlId={id} bsSize="small">
<ControlLabel>{label}</ControlLabel>
<FormControl {...props} ref={ref} />
{help && <HelpBlock>{help}</HelpBlock>}
</FormGroup>
);
});

How to show error on button click in React native?

I am using 'react-native-material-textfield' and it working well, but I need to show error for empty field when clicking on submit button. I have searched lot-of but didn't find any solution.
Put the error message in your state and fill it with a message after clicking on the submit button, if your validation process fails.
render(){
return (
<View>
<TextField
{...props}
error={this.state.error}
errorColor={'red'}
onFocus={() => this.setState({error: ''})}
/>
<Button {...props} />
</View>)}
Check the example on the developers github repository.
According to the module documentation and examples, whenever your this.state.errors for each field is not empty, its error is shown. So your form should look like this:
class Form extends Component {
// ... Some required methods
onSubmit() {
let errors = {};
['firstname'] // This array should be filled with your fields names.
.forEach((name) => {
let value = this[name].value();
if (!value) {
errors[name] = 'Should not be empty'; // The error message when field is empty
}
});
this.setState({ errors });
}
render() {
let { errors = {}, data } = this.state;
return (
<View>
<TextField
value={data.firstname}
onChangeText={this.onChangeText}
error={errors.firstname}
/>
<Text onPress={this.onSubmit}>Submit</Text>
</View>
);
}
}

In list component, how to implement a component to change the number of results displayed

I was thinking about making a simple component with a Select and the list of results that should be displayed.
After reading the code, that seems impossible, because if I change the url, then update is triggered by componentWillReceiveProps, and this method does not check for a change of perPage
Change the prop perPage of the List component does not work either because the List use this prop only if the query does not already contains perPage
Here is an example of what I want to do :
import { List } from "admin-on-rest";
class SourceList extends Component {
constructor(props) {
super(props);
this.state = {
perPage: 10
};
}
render() {
return (
<div>
<Button
onClick={() => {
this.setState({ perPage: 50 });
}}
/>
<List {...props} perPage={this.state.perPage}>
... Here would be the content of the list
</List>
</div>
);
}
}

How to use Redux-Form with React-Bootstrap?

I am trying to use "redux-form": "^6.7.0" with "react-bootstrap": "^0.31.0"
My Component renders nicely, but when I press Submit, what I see is an empty object.
note: I have tried wrapping the Config with connect first, and as show below, first wraping it with redux-form and then with the from react-redux connect()
Configuration.js
class Config extends Component {
render() {
const { ServerPort, UserID, PortNumber, WWWUrl, SourcePath, FMEPath, pickFile, pickFolder, handleSubmit } = this.props;
return (
<Form horizontal onSubmit={handleSubmit}>
<FormGroup controlId="serverPortBox">
<Col componentClass={ControlLabel} sm={2}>Watson Port:</Col>
<Col sm={10}>
<OverlayTrigger placement="left" overlay={(<Tooltip id="tt1">TCP port for Watson to use</Tooltip>)}>
<Field name="WatsonPort" component={FormControl}
type="number" min="1024" max="65535" placeholder={ServerPort} />
</OverlayTrigger>
</Col>
</FormGroup>
......
const CForm = reduxForm({
form: 'configuration' // a unique name for this form
})(Config);
const Configuration = connect(mapStateToProps, mapDispatchToProps)(CForm)
export default Configuration
reducers.js
import { combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form
......
const reducerList = {
GLVersion,
ServerConfig,
ServerStats,
form: formReducer
}
export default combineReducers(reducerList)
Main Package Dashboard.js
what i see in the debugger is that config is an empty object
<Panel className='configPanel'
collapsible header="Configuration"
eventKey="1"
defaultExpanded={true}>
<Configuration onSubmit={(config) => writeConfig(config)} />
</Panel>
See: https://github.com/erikras/redux-form/issues/2917
Oh, this was a great mystery. I followed the advice in https://github.com/react-bootstrap/react-bootstrap/issues/2210 and both the warning about additional props and the empty submit stopped.
It seems you have to wrap the Bootstrap in your custom component (why?, I don't know). Also make sure you custom component is a stateless funcitonal component, or after the first key press, you field will blur and lose focus.
There are some warnings in the documentation of redux-form about this.
my custom field component FieldInput
const FieldInput = ({ input, meta, type, placeholder, min, max }) => {
return (
<FormControl
type={type}
placeholder={placeholder}
min={min}
max={max}
value={input.value}
onChange={input.onChange} />
)
}
and I invoke it like this:
<Field name="ServerPort"
type='number'
component={FieldInput}
placeholder={ServerPort}
min="1024" max="65535"
/>
see also: https://github.com/erikras/redux-form/issues/1750
So now, the definition of FieldInput and Config look like this:
import React, { Component } from 'react'
import { Field, reduxForm } from 'redux-form'
import { connect } from 'react-redux'
import { Form, FormControl, FormGroup, ControlLabel, Col, Button, Tooltip, OverlayTrigger } from 'react-bootstrap'
import * as Act from '../dash/actions.js'
import FaFolderOpen from 'react-icons/lib/fa/folder-open'
import FaFileCodeO from 'react-icons/lib/fa/file-code-o'
const FieldInput = ({ input, meta, type, placeholder, min, max }) => {
return (
<FormControl
type={type}
placeholder={placeholder}
min={min}
max={max}
value={input.value}
onChange={input.onChange} />
)
}
const Config = ({ ServerPort, UserID, PortNumber, WWWUrl, SourcePath, FMEPath, pickFile, pickFolder, handleSubmit }) => {
return (
<Form horizontal onSubmit={handleSubmit}>
<FormGroup controlId="serverPortBox">
<Col componentClass={ControlLabel} sm={2}>Watson Port:</Col>
<Col sm={10}>
<OverlayTrigger placement="left" overlay={(<Tooltip id="tt1">TCP port for Watson to use</Tooltip>)}>
<Field name="ServerPort" type='number' min="1024" max="65535" component={FieldInput} placeholder={ServerPort} />
</OverlayTrigger>
</Col>
</FormGroup>
Some props required by <FormControl> are passed inside props.input from <Field>, see http://redux-form.com/6.6.3/docs/api/Field.md/#props
To pass all those props in a generic way, instead of doing it explicitly, you can use the following function:
const ReduxFormControl = ({input, meta, ...props}) => {
return <FormControl {...props} {...input} />
};
and then inside the form:
<Field component={ReduxFormControl} ... />
This way, value, onChange, etc. are all passed as expected to <FormControl>.

the selected option will be restored to unselected status

3sec Demo https://www.youtube.com/watch?v=bo2nNQXbhI8&feature=youtu.be
https://gist.github.com/weichenghsu/407a8862f3382a425fb531b3dedcd6f5
As title, the selected option will be restored to unselected status
And onChange method has no effect for the official tutorial example.
My use case is that when a user picks a value from the dropdown. It should fire an action to fetch other data and render on another form
const chooseTable = ({items, meta:{touched, error}}) => (
<select
onChange={event => {
console.log(this.props.fields);
this.props.tableNameOnChange(event.target.value);
}}>
<option value="">Select</option>
{
items.map((item :any, i: integer) =>
<option key={item.id} value={item.id}>{item.name}</option>
)
}
</select>
)
<Field component={chooseTable}
items={schemaData.tableList}
name="tableName"
>
{/*<option value="#ff0000">Red</option>*/}
{/*<option value="#00ff00">Green</option>*/}
{/*<option value="#0000ff">Blue</option>*/}
</Field>
UIBuilderForm = reduxForm({
form: 'dashbaordUiBuilderForm',
fields: ['tableName']
}
})
(UIBuilderForm as any);
// Decorate with connect to read form values
const selector = formValueSelector('dashbaordUiBuilderForm')
// export default connect(mapStateToProps, mapDispatchToProps)(UIBuilderForm);
export default connect(state => {
const TableSchemaName = selector(state, 'TableSchemaName')
return {
TableSchemaName
}
}
I was banging my head on a similar issue with the react-native picker. Try writing your 'chooseTable' as a component instead of a stateless function and use 'this.state' and 'this.setState' to refer to what value is selected. Here's an example from my picker code:
class ExpirePicker extends React.Component {
constructor(props) {
super(props)
this.state = {
selected: 'ASAP'
}
}
render() {
const { input: { onChange, ...rest }} = this.props
return (
<Picker
style={style.input}
selectedValue={this.state.selected}
onValueChange={(value) => {
this.setState({selected: value})
onChange(value)
}}
{...rest}>
{Object.keys(ExpireTypes).map(renderItem)}
</Picker>
)
}
}
Could you also be using the element's "onChange" event and not binding it to redux-forms "onChange" prop?

Resources