admin-on-rest-fr05t1k
Version:
A frontend Framework for building admin applications on top of REST services, using ES6, React and Material UI
309 lines (267 loc) • 10.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ReferenceInput = undefined;
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactRedux = require('react-redux');
var _lodash = require('lodash.debounce');
var _lodash2 = _interopRequireDefault(_lodash);
var _Labeled = require('./Labeled');
var _Labeled2 = _interopRequireDefault(_Labeled);
var _dataActions = require('../../actions/dataActions');
var _possibleValues = require('../../reducer/references/possibleValues');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var referenceSource = function referenceSource(resource, source) {
return resource + '@' + source;
};
var noFilter = function noFilter() {
return true;
};
/**
* An Input component for choosing a reference record. Useful for foreign keys.
*
* This component fetches the possible values in the reference resource
* (using the `CRUD_GET_MATCHING` REST method), then delegates rendering
* to a subcomponent, to which it passes the possible choices
* as the `choices` attribute.
*
* Use it with a selector component as child, like `<AutocompleteInput>`,
* `<SelectInput>`, or `<RadioButtonGroupInput>`.
*
* @example
* export const CommentEdit = (props) => (
* <Edit {...props}>
* <SimpleForm>
* <ReferenceInput label="Post" source="post_id" reference="posts">
* <AutocompleteInput optionText="title" />
* </ReferenceInput>
* </SimpleForm>
* </Edit>
* );
*
* @example
* export const CommentEdit = (props) => (
* <Edit {...props}>
* <SimpleForm>
* <ReferenceInput label="Post" source="post_id" reference="posts">
* <SelectInput optionText="title" />
* </ReferenceInput>
* </SimpleForm>
* </Edit>
* );
*
* By default, restricts the possible values to 25. You can extend this limit
* by setting the `perPage` prop.
*
* @example
* <ReferenceInput
* source="post_id"
* reference="posts"
* perPage={100}>
* <SelectInput optionText="title" />
* </ReferenceInput>
*
* By default, orders the possible values by id desc. You can change this order
* by setting the `sort` prop (an object with `field` and `order` properties).
*
* @example
* <ReferenceInput
* source="post_id"
* reference="posts"
* sort={{ field: 'title', order: 'ASC' }}>
* <SelectInput optionText="title" />
* </ReferenceInput>
*
* Also, you can filter the query used to populate the possible values. Use the
* `filter` prop for that.
*
* @example
* <ReferenceInput
* source="post_id"
* reference="posts"
* filter={{ is_published: true }}>
* <SelectInput optionText="title" />
* </ReferenceInput>
*
* The enclosed component may filter results. ReferenceInput passes a `setFilter`
* function as prop to its child component. It uses the value to create a filter
* for the query - by default { q: [searchText] }. You can customize the mapping
* searchText => searchQuery by setting a custom `filterToQuery` function prop:
*
* @example
* <ReferenceInput
* source="post_id"
* reference="posts"
* filterToQuery={searchText => ({ title: searchText })}>
* <SelectInput optionText="title" />
* </ReferenceInput>
*/
var ReferenceInput = exports.ReferenceInput = function (_Component) {
(0, _inherits3.default)(ReferenceInput, _Component);
function ReferenceInput(props) {
(0, _classCallCheck3.default)(this, ReferenceInput);
var _this = (0, _possibleConstructorReturn3.default)(this, (ReferenceInput.__proto__ || Object.getPrototypeOf(ReferenceInput)).call(this, props));
_initialiseProps.call(_this);
var perPage = props.perPage,
sort = props.sort,
filter = props.filter;
// stored as a property rather than state because we don't want redraw of async updates
_this.params = { pagination: { page: 1, perPage: perPage }, sort: sort, filter: filter };
_this.debouncedSetFilter = (0, _lodash2.default)(_this.setFilter.bind(_this), 500);
return _this;
}
(0, _createClass3.default)(ReferenceInput, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.fetchReferenceAndOptions();
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (this.props.record.id !== nextProps.record.id) {
this.fetchReferenceAndOptions(nextProps);
}
}
}, {
key: 'fetchReferenceAndOptions',
value: function fetchReferenceAndOptions() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props,
input = _ref.input,
reference = _ref.reference,
source = _ref.source,
resource = _ref.resource;
var _params = this.params,
pagination = _params.pagination,
sort = _params.sort,
filter = _params.filter;
var id = input.value;
if (id) {
this.props.crudGetOne(reference, id, null, false);
}
this.props.crudGetMatching(reference, referenceSource(resource, source), pagination, sort, filter);
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
input = _props.input,
resource = _props.resource,
label = _props.label,
source = _props.source,
reference = _props.reference,
referenceRecord = _props.referenceRecord,
allowEmpty = _props.allowEmpty,
matchingReferences = _props.matchingReferences,
basePath = _props.basePath,
onChange = _props.onChange,
children = _props.children,
meta = _props.meta;
if (!referenceRecord && !allowEmpty) {
return _react2.default.createElement(_Labeled2.default, {
label: typeof label === 'undefined' ? 'resources.' + resource + '.fields.' + source : label,
source: source,
resource: resource
});
}
return _react2.default.cloneElement(children, {
allowEmpty: allowEmpty,
input: input,
label: typeof label === 'undefined' ? 'resources.' + resource + '.fields.' + source : label,
resource: resource,
meta: meta,
source: source,
choices: matchingReferences,
basePath: basePath,
onChange: onChange,
filter: noFilter, // for AutocompleteInput
setFilter: this.debouncedSetFilter,
setPagination: this.setPagination,
setSort: this.setSort,
translateChoice: false
});
}
}]);
return ReferenceInput;
}(_react.Component);
var _initialiseProps = function _initialiseProps() {
var _this2 = this;
this.setFilter = function (filter) {
if (filter !== _this2.params.filter) {
_this2.params.filter = _this2.props.filterToQuery(filter);
_this2.fetchReferenceAndOptions();
}
};
this.setPagination = function (pagination) {
if (pagination !== _this2.param.pagination) {
_this2.param.pagination = pagination;
_this2.fetchReferenceAndOptions();
}
};
this.setSort = function (sort) {
if (sort !== _this2.params.sort) {
_this2.params.sort = sort;
_this2.fetchReferenceAndOptions();
}
};
};
ReferenceInput.propTypes = {
addField: _react.PropTypes.bool.isRequired,
allowEmpty: _react.PropTypes.bool.isRequired,
basePath: _react.PropTypes.string,
children: _react.PropTypes.element.isRequired,
crudGetMatching: _react.PropTypes.func.isRequired,
crudGetOne: _react.PropTypes.func.isRequired,
filter: _react.PropTypes.object,
filterToQuery: _react.PropTypes.func.isRequired,
input: _react.PropTypes.object.isRequired,
label: _react.PropTypes.string,
matchingReferences: _react.PropTypes.array,
meta: _react.PropTypes.object,
onChange: _react.PropTypes.func,
perPage: _react.PropTypes.number,
reference: _react.PropTypes.string.isRequired,
referenceRecord: _react.PropTypes.object,
resource: _react.PropTypes.string.isRequired,
sort: _react.PropTypes.shape({
field: _react.PropTypes.string,
order: _react.PropTypes.oneOf(['ASC', 'DESC'])
}),
source: _react.PropTypes.string
};
ReferenceInput.defaultProps = {
addField: true,
allowEmpty: false,
filter: {},
filterToQuery: function filterToQuery(searchText) {
return { q: searchText };
},
matchingReferences: [],
perPage: 25,
sort: { field: 'id', order: 'DESC' },
referenceRecord: null
};
function mapStateToProps(state, props) {
var referenceId = props.input.value;
return {
referenceRecord: state.admin[props.reference].data[referenceId],
matchingReferences: (0, _possibleValues.getPossibleReferences)(state, referenceSource(props.resource, props.source), props.reference, referenceId)
};
}
var ConnectedReferenceInput = (0, _reactRedux.connect)(mapStateToProps, {
crudGetOne: _dataActions.crudGetOne,
crudGetMatching: _dataActions.crudGetMatching
})(ReferenceInput);
ConnectedReferenceInput.defaultProps = {
addField: true
};
exports.default = ConnectedReferenceInput;