Hello,
I tried to create a "between" like filter with 2 DateInput :
import React, { Component, PropTypes } from 'react';
import { Field } from 'redux-form';
import { DateInput } from 'admin-on-rest';
class PeriodInput extends Component {
render() {
const styles = {
row: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-between',
},
};
return (
<span style={styles.row}>
<Field
name={this.props.fromSource}
label={this.props.fromLabel}
component={DateInput}
/>
<Field
name={this.props.toSource}
label={this.props.toLabel}
component={DateInput}
/>
</span>
);
}
}
PeriodInput.propTypes = {
fromSource: PropTypes.string.isRequired,
fromLabel: PropTypes.string.isRequired,
toSource: PropTypes.string.isRequired,
toLabel: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
};
PeriodInput.defaultProps = {
addLabel: true,
label: 'Position',
};
export default PeriodInput;
import React, { Component } from 'react';
import {
List,
Datagrid,
TextField,
ReferenceField,
DateField,
NumberField,
ReferenceManyField,
ChipField,
SingleFieldList,
EditButton,
Filter,
DateInput,
} from 'admin-on-rest';
import PeriodInput from '../common/periodInput';
export default class MoveList extends Component {
render() {
const MoveFilter = props => (
<Filter {...props}>
<DateInput label="resources.moves.fields.endDate_gte" source="endDate_gte" />
<DateInput label="resources.moves.fields.startDate_lte" source="startDate_lte" />
<PeriodInput
source="between"
fromLabel="resources.moves.fields.endDate_intersect_1"
fromSource="endDate_intersect_1_gte"
toLabel="resources.moves.fields.startDate_intersect_1"
toSource="startDate_intersect_1_lte"
label="resources.moves.filters.intersect"
/>
</Filter>
);
return (
<List filters={<MoveFilter />} {...this.props}>
<Datagrid>
<DateField label="resources.moves.fields.startDate" source="startDate" />
<DateField label="resources.moves.fields.endDate" source="endDate" />
<TextField label="resources.moves.fields.name" source="name" />
<ReferenceField label="resources.moves.fields.zone" source="zoneId" reference="zones" linkType={false}>
<TextField source="name" />
</ReferenceField>
<NumberField label="resources.moves.fields.id" source="id" />
<ReferenceManyField perPage={5} label="resources.moves.fields.users" target="moveId" reference="movessgusers">
<SingleFieldList>
<ReferenceField source="sgUserId" reference="sgusers" linkType={false}>
<ChipField source="email" />
</ReferenceField>
</SingleFieldList>
</ReferenceManyField>
<EditButton />
</Datagrid>
</List>
);
}
}
The filter works, when I choose it from the filters list, the two fields display well, I can choose dates and filter as expected. But when I use the cross to clear the filter, it does disapear, but it's not cleared as wanted. Clicking again on the filter in the filters list, display the filter with the previsously chosen values.
Thanks for your help !
PS: you always need to set the source property for the input in filters if you want to avoid a hideFilter console error.
Same here
I'm surprised it even works the first time - the filter system wasn't designed to support combined filters. I consider it an enhancement request.
@fzaninotto Yes, after looking at the filters code, I was surprised too.
I was expecting it to work though, since the documentation specify filters expect an input field and the example for custom input fields is actually composed by 2 fields.
Hi.
@gandrin this specific feature is working. I've just test it use the following code.
<PeriodInput
source="between"
fromLabel="from"
fromSource="between.gte"
toLabel="to"
toSource="between.lte"
label="period"
/>
you can use more than one field. and this is the solution i've searching for.
so the code remove the filter name as mentioned in source.
so if you just rename fields, remove filter button will work fine.
but also we can just replace
return (
<span style={styles.row}>
<Field
name={`${this.props.source}.gte`} //<<<
label={this.props.fromLabel}
component={DateInput}
/>
<Field
name={`${this.props.source}.lte`}//<<<
label={this.props.toLabel}
component={DateInput}
/>
</span>
);
Hi.
my implementation:
//DateBetweenInput.js
import React, { Component } from 'react';
import { DateInput } from 'react-admin';
import { addField } from 'ra-core';
class DateBetweenInput extends Component {
render() {
const styles = {
row: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-between',
},
};
const {resource, source } = this.props
return (
<span style={styles.row}>
<DateInput
source={`${source}_gte`}
label={`resources.${resource}.fields.${source}_gte`}
/>
<DateInput
source={`${source}_lte`}
label={`resources.${resource}.fields.${source}_lte`}
/>
</span>
);
}
}
DateBetweenInput.defaultProps = {
addLabel: true,
label: 'createdAt',
};
export default addField(DateBetweenInput);
//index.js
...
const OrderFilter = (props) => (
<Filter {...props}>
<SearchInput source="q" alwaysOn />
<DateBetweenInput source="createdAt" />
</Filter>
...
I'm new, and I have a few questions:
Thanks @wmwart , I extracted this to a reusable component:
import React from "react";
const styles = {
row: {
display: "flex",
flexDirection: "row",
alignItems: "flex-start",
justifyContent: "space-between",
},
};
export class InputRow extends React.PureComponent {
render() {
const { children, ...rest } = this.props;
return (
<span style={styles.row}>
{React.Children.map(children, child => {
return React.cloneElement(child, rest);
})}
</span>
);
}
}
and now you can just wrap any inputs with it:
<InputRow>
<TextInput source="field1" />
<TextInput source="field2" />
</InputRow>
Still seems this doesn't work to clear the combined input filter? Anyone found a solution to this yet?
In case somebody is still stuck clearing custom or multiple filters:
First, be careful with @waynebloss solution based on @wmwart's. It won't put labels on the filter dropdown because you are missing the source on the main component, wich RA's FilterButton uses to put labels on the dropdown. You can work around this by setting source on the InputRow and not using it on children like this
<MultipleFilter source="nameOfTheFilter">
<Textinput source="nameOfTheFilter_lt" />
<Textinput source="nameOfTheFilter_gt" />
</MultipleFilter>
// ... In your component
const MultipleFilter = ({ children, source, ...rest }) => (
<span style={styles.row}>
{React.Children.map(children, (child) => {
return React.cloneElement(child, rest);
})}
</span>
);
But RA does not know to clear those inputs, it will only clear the "aggregated source name" and let others as they are.
One idea could be just implementing your backend to ignore filters when there's no aggregated filter present. If you send "nameOfTheFilter", that has inside "nameOfTheFilter_gt" and "nameOfTheFilter_lt" just don't filter by any of them unless "nameOfTheFilter" is present.
The only "workaround" I found without backend code is implement everything as custom, from the input to the filters and filter consolidation system, and it's not worth it, you'd be better not using React Admin at all.
Most helpful comment
Hi.
my implementation:
I'm new, and I have a few questions: