I have to load a select input options depends on another select input value
<SimpleForm validate={validateUnitForm} >
<ReferenceInput label="District" source="districtId" reference="districts" allowEmpty >
<SelectInput optionText="name" />
</ReferenceInput>
<TextInput source="name" />
<ZoneInput dependsOn="districtId">
<ReferenceInput label="Zone" source="zoneId" reference="zones" allowEmpty>
<SelectInput optionText="name" />
</ReferenceInput>
</ZoneInput>
</SimpleForm>
I have created something like below
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { formValueSelector, getFormValues } from 'redux-form';
import FormField from 'admin-on-rest/lib/mui/form/FormField';
const REDUX_FORM_NAME = 'record-form';
export const ZoneInput = ({ children, dependsOn, dependsOnValue, ...props }) => {
const selectedInput = React.cloneElement(children, {
filter: { districtId: dependsOnValue },
})
return (
<div key={children.props.source} style={children.props.style} className={`aor-input-${children.props.source}`}>
<FormField input={selectedInput} {...props} />
</div>
);
};
ZoneInput.propTypes = {
children: PropTypes.node.isRequired,
dependsOn: PropTypes.any,
dependsOnValue: PropTypes.any,
formName: PropTypes.string,
};
export const mapStateToProps = (state, { dependsOn, formName = REDUX_FORM_NAME }) => {
const formValue = formValueSelector(formName)(state, dependsOn);
return { dependsOnValue: formValue };
};
export default connect(mapStateToProps)(ZoneInput);
But ReferenceInput filter props does not accepting dynamic values it is not working when we change the filter props
The following line seems like an issue
https://github.com/marmelab/admin-on-rest/blob/master/src/mui/input/ReferenceInput.js#L137
But I changed it and tested but not working
Are you aware of aor-dependent-input ?
@djhi Yes I tried the same logic here for my Zone Input Component but I don't need to have a separate API call I can simply use state change in the Create component as below
<ReferenceInput label="Zone" source="zoneId" reference="zones" allowEmpty filter={{ditrictId: this.state.districtId}}>
<SelectInput optionText="name" />
</ReferenceInput>
But the filter prop will not work with state changes or propvalue changes.
separate API call ?
As described here
https://github.com/marmelab/aor-dependent-input#re-rendering-the-dependentinput-children-when-the-values-of-the-dependencies-change
I have the same scenario but no need to have an API call !
Then, just don't call an api ?
Let me try..
I have used the following code for getting the select input load based on another select input
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import debounce from 'lodash.debounce';
import { Labeled } from 'admin-on-rest';
import { formValueSelector } from 'redux-form';
import {
crudGetOne as crudGetOneAction,
crudGetMatching as crudGetMatchingAction,
} from 'admin-on-rest/lib/actions/dataActions';
import { getPossibleReferences } from 'admin-on-rest/lib/reducer/admin/references/possibleValues';
const REDUX_FORM_NAME = 'record-form';
const referenceSource = (resource, source) => `${resource}@${source}`;
const noFilter = () => true;
export class DepOnRefInput extends Component {
constructor(props) {
super(props);
const { perPage, sort, filter } = props;
// stored as a property rather than state because we don't want redraw of async updates
this.params = { pagination: { page: 1, perPage }, sort, filter };
this.debouncedSetFilter = debounce(this.setFilter.bind(this), 500);
}
componentDidMount() {
this.fetchReferenceAndOptions();
}
componentWillReceiveProps(nextProps) {
if (this.props.record.id !== nextProps.record.id || this.props.dependsOnValue !== nextProps.dependsOnValue ) {
this.fetchReferenceAndOptions(nextProps);
}
}
setFilter = filter => {
if (filter !== this.params.filter) {
this.params.filter = this.props.filterToQuery(filter);
this.fetchReferenceAndOptions();
}
};
setPagination = pagination => {
if (pagination !== this.param.pagination) {
this.param.pagination = pagination;
this.fetchReferenceAndOptions();
}
};
setSort = sort => {
if (sort !== this.params.sort) {
this.params.sort = sort;
this.fetchReferenceAndOptions();
}
};
fetchReferenceAndOptions(
{ input, reference, source, resource, dependsOn, dependsOnValue } = this.props
) {
const { filter: filterFromProps } = this.props;
const { pagination, sort, filter } = this.params;
const id = input.value;
if (id) {
this.props.crudGetOne(reference, id, null, false);
}
let finalFilter = { ...filterFromProps, ...filter };
finalFilter[dependsOn] = dependsOnValue;
this.props.crudGetMatching(
reference,
referenceSource(resource, source),
pagination,
sort,
finalFilter
);
}
render() {
const {
input,
resource,
label,
source,
referenceRecord,
allowEmpty,
matchingReferences,
basePath,
onChange,
children,
meta,
} = this.props;
if (!referenceRecord && !allowEmpty) {
return (
<Labeled
label={
typeof label === 'undefined' ? (
`resources.${resource}.fields.${source}`
) : (
label
)
}
source={source}
resource={resource}
/>
);
}
return React.cloneElement(children, {
allowEmpty,
input,
label:
typeof label === 'undefined'
? `resources.${resource}.fields.${source}`
: label,
resource,
meta,
source,
choices: matchingReferences,
basePath,
onChange,
filter: noFilter, // for AutocompleteInput
setFilter: this.debouncedSetFilter,
setPagination: this.setPagination,
setSort: this.setSort,
translateChoice: false,
});
}
}
DepOnRefInput.propTypes = {
addField: PropTypes.bool.isRequired,
allowEmpty: PropTypes.bool.isRequired,
basePath: PropTypes.string,
children: PropTypes.element.isRequired,
crudGetMatching: PropTypes.func.isRequired,
crudGetOne: PropTypes.func.isRequired,
filter: PropTypes.object,
filterToQuery: PropTypes.func.isRequired,
input: PropTypes.object.isRequired,
label: PropTypes.string,
matchingReferences: PropTypes.array,
meta: PropTypes.object,
onChange: PropTypes.func,
perPage: PropTypes.number,
reference: PropTypes.string.isRequired,
referenceRecord: PropTypes.object,
resource: PropTypes.string.isRequired,
sort: PropTypes.shape({
field: PropTypes.string,
order: PropTypes.oneOf(['ASC', 'DESC']),
}),
source: PropTypes.string,
dependsOnValue: PropTypes.any,
};
DepOnRefInput.defaultProps = {
addField: true,
allowEmpty: false,
filter: {},
filterToQuery: searchText => ({ q: searchText }),
matchingReferences: [],
perPage: 25,
sort: { field: 'id', order: 'DESC' },
referenceRecord: null,
};
function mapStateToProps(state, props) {
const referenceId = props.input.value;
const dependsOn = props.dependsOn;
const formName = props.formName || REDUX_FORM_NAME;
const formValue = formValueSelector(formName)(state, dependsOn);
return {
referenceRecord:
state.admin.resources[props.reference].data[referenceId],
matchingReferences: getPossibleReferences(
state,
referenceSource(props.resource, props.source),
props.reference,
),
dependsOnValue: formValue,
};
}
const ConnectedDepOnRefInput = connect(mapStateToProps, {
crudGetOne: crudGetOneAction,
crudGetMatching: crudGetMatchingAction,
})(DepOnRefInput);
ConnectedDepOnRefInput.defaultProps = {
addField: true,
};
export default ConnectedDepOnRefInput;
It can be used same as the ReferenceInput as below
<Create {...props}>
<SimpleForm validate={validateUnitForm} >
<ReferenceInput label="District" source="districtId" reference="districts" allowEmpty >
<SelectInput optionText="name" />
</ReferenceInput>
<TextInput source="name" />
<DepOnRefInput label="Zone" source="zoneId" reference="zones" dependsOn="districtId" allowEmpty>
<SelectInput optionText="name" />
</DepOnRefInput>
</SimpleForm>
</Create>
@mshameer I have the same issue. Have you find a way around it?
@themalkolm Yes. Please check my previous comment. I have created another component <DepOnRefInput> which will support all the props of ReferenceInput. I have added one more props to it as dependsOn in which we can add the resource to be watched for changes
Hi, and thanks for your question. As explained in the admin-on-rest contributing guide, the right place to ask a "How To" question, get usage advice, or troubleshoot your own code, is StackOverFlow.
This makes your question easy to find by the core team, and the developer community. Unlike Github, StackOverFlow has great SEO, gamification, voting, and reputation. That's why we chose it, and decided to keep GitHub issues only for bugs and feature requests.
So I'm closing this issue, and inviting you to ask your question at:
http://stackoverflow.com/questions/tagged/admin-on-rest
And once you get a response, please continue to hang out on the admin-on-rest channel in StackOverflow. That way, you can help newcomers and share your expertise!
@mshameer thanks! My bad for missing it.
Most helpful comment
I have used the following code for getting the select input load based on another select input
It can be used same as the
ReferenceInputas below