New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ReferenceManyInput #484
Conversation
# Conflicts: # src/mui/input/ArrayInput.js
# Conflicts: # src/mui/input/SelectManyInput.js
Can you please PR against the |
OK. |
DONE. But look like no new travis build against |
@fzaninotto Is it OK? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super encouraging, looking forward to merging this one! Your PR needs a few changes before that.
src/mui/input/ReferenceManyInput.js
Outdated
@@ -0,0 +1,222 @@ | |||
import React, {Component, PropTypes} from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CS: please add spaces inside brackets. {Component, PropTypes}
=> { Component, PropTypes }
This happens in many places in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:D The IntelliJ auto formatting...
src/mui/input/ReferenceManyInput.js
Outdated
const noFilter = () => true; | ||
|
||
/** | ||
* An Input component for choosing many reference records. Useful for 'hasMany' relationship. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to show the expected value in the record (an array of ids)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean, I need to provide detailed comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
src/mui/input/SelectManyInput.js
Outdated
* | ||
* Pass possible options as an array of objects in the 'choices' attribute. | ||
* @example | ||
* const choices = [ 'Male', 'Female' ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't agree with the addition of this type
prop. It complicates things IMO. Keep to the same API as SelectInput
and remove the type
prop.
src/mui/input/ReferenceManyInput.js
Outdated
const {pagination, sort, filter} = this.params; | ||
const ids = input.value; | ||
if (ids && Array.isArray(ids)) { | ||
this.props.crudGetMany(reference, ids); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should probably throw an explicit error if ids
is not an array.
src/mui/input/ReferenceManyInput.js
Outdated
* <SelectManyInput type="object" optionText="title" /> | ||
* </ReferenceManyInput> | ||
*/ | ||
export class ReferenceManyInput extends Component { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my 2c: as there is a lot of common code with ReferenceInput
, why don't you extend ReferenceInput
instead of Component
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will try to do so... :)
src/mui/input/SelectManyInput.js
Outdated
export class SelectManyInput extends Component { | ||
// Comment input onBlur because SelectManyInput don't pass correct values on this event | ||
handleBlur = (eventOrValue) => { | ||
// this.props.onBlur(eventOrValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented out code
src/mui/input/SelectManyInput.js
Outdated
* @see https://github.com/TeamWertarbyte/material-ui-chip-input | ||
*/ | ||
export class SelectManyInput extends Component { | ||
// Comment input onBlur because SelectManyInput don't pass correct values on this event |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand, can you elaborate? Not catching onBlur
or onFocus
from the child component will probably break redux-form validation
src/mui/input/SelectManyInput.js
Outdated
}; | ||
// Comment input onFocus because SelectManyInput don't pass correct values on this event | ||
handleFocus = (event) => { | ||
// this.props.onFocus(event); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, please don't commit commented out code
src/mui/input/SelectManyInput.js
Outdated
|
||
handleChange = (eventOrValue) => { | ||
if (this.props.type == 'object') { | ||
eventOrValue = this.extractIds(eventOrValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't modify a parameter of the function. Use a new const
instead
src/mui/input/SelectManyInput.js
Outdated
type, | ||
} = this.props; | ||
|
||
// Always use uncontrolled mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand. On the contrary, we should use controlled mode, shouldn't we?
Any updates on this one? |
Sorry, I'm on vacation now, I will back in 2 more days... :) |
I'm very interested in this component so I try to implement it with your code. Some points I see (I'm new with redux-form/admin-on-rest so maybe I'm wrong!):
FYI, my handleAdd = (newValue) => {
const { input: { value, onChange } } = this.props;
onChange([...value, ...[newValue.id]]);
};
handleDelete = (newValue) => {
const { input: { value, onChange } } = this.props;
onChange(value.filter(v => (v != newValue)));
}; EDIT: EDIT2: <ChipInput
onBlur={() => this.props.onBlur(defaultValue)}
onFocus={() => this.props.onFocus(defaultValue)}
/> |
In function mapStateToProps(state, props) {
const referenceIds = props.input.value;
const referenceRecords = [];
let matchingReferences = [];
const data = state.admin[props.reference].data;
if (!referenceIds.length) {
matchingReferences = getPossibleReferences(state, referenceSource(props.resource, props.source), props.reference);
} else {
for (let i = 0; i < referenceIds.length; i++) {
if (data[referenceIds[i]]) {
referenceRecords.push(data[referenceIds[i]]);
const possibleReferences = getPossibleReferences(state, referenceSource(props.resource, props.source), props.reference, referenceIds[i]);
matchingReferences = Object.assign(matchingReferences, possibleReferences);
}
}
}
return {
referenceRecords: referenceRecords,
matchingReferences: matchingReferences,
}
} In However, the Further, when the function is called, the default filters are erased by
My second call:
I know you use the same code as |
any ETA on this one? We'll be releasing 1.0 within a week, and I'd love to see it merged. |
|
@fzaninotto Please check again! 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still some work to do. Also, could you document the two fields in docs/Inputs.md
?
src/mui/input/ReferenceManyInput.js
Outdated
* | ||
* @example | ||
* { | ||
* postIds: [ "1", "23", "4" ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following example (and the ones below) uses post_id
and this one postIds
. Please make them consistent. I think it should be post_ids
everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
src/mui/input/ReferenceManyInput.js
Outdated
choices: matchingReferences, | ||
basePath, | ||
onChange, | ||
filter: noFilter, // for AutocompleteInput |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bump
src/mui/input/ReferenceManyInput.js
Outdated
filter: {}, | ||
filterToQuery: searchText => ({ q: searchText }), | ||
matchingReferences: [], | ||
meta: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed this one from other components because it has side effects, please remove it here, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you mean the filter
and filterToQuery
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, I mean meta
. Use other components as models.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
if (!referenceIds.length) { | ||
matchingReferences = getPossibleReferences(state, referenceSource(props.resource, props.source), props.reference); | ||
} else { | ||
for (let i = 0; i < referenceIds.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be placed in a selector, otherwise it's executed for every global state change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see... But what should I do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create a selector in the reducer - there are others like it (see https://github.com/marmelab/admin-on-rest/blob/master/src/reducer/references/oneToMany.js#L19-L29)
src/mui/input/SelectManyInput.js
Outdated
import FieldTitle from '../../util/FieldTitle'; | ||
|
||
/** | ||
* An Input component for a array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/for a array/for an array/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
src/mui/input/SelectManyInput.js
Outdated
* An Input component for a array | ||
* | ||
* @example | ||
* <SelectManyInput source="first_name" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bad example. How can first_name
be an array? Same for the rest of the comments for that component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
src/mui/input/SelectManyInput.js
Outdated
}; | ||
|
||
extractIds = (eventOrValue) => { | ||
let value = eventOrValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it a const
by using a ternary expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
src/mui/input/SelectManyInput.js
Outdated
return this.props.choices.filter((o) => ids.indexOf(o[this.props.optionValue]) >= 0); | ||
} else { | ||
return ids.map((id) => { | ||
let o = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better return an object literal directly:
return ids.map((id) => ({
[this.props.optionValue]: id,
[this.props.optionText]: id,
}))
Also, how come you use the id both for value and text?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will change the variable name... 👍
|
||
handleChange = (eventOrValue) => { | ||
var extracted = this.extractIds(eventOrValue); | ||
this.props.onChange(extracted); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's this onChange
for? Same for the other custom handlers (onBlur
, etc): they don't exist in other components, so it doesn't make sense to add them just for that component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure... I copied from TextInput
, what's it for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the doc:
Some other props are progressively implemented. The
<TextInput />
and<NumberInput />
inputs also accept following props:
onBlur
: [...]
onChange
: [...]
onFocus
: [...]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my bad, you're right
src/mui/input/SelectManyInput.js
Outdated
} = this.props; | ||
|
||
// Convert the name of fields in choices | ||
options['dataSourceConfig'] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use dot notation. same for dataSource
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're getting very close. To do before merge:
- Move the logic from
mapStateToProps
to a selector - Add documentation for the 2 new inputs
src/mui/input/SelectManyInput.js
Outdated
|
||
if (this.props.choices && this.props.choices.length > 0) { | ||
return this.props.choices.filter((o) => values.indexOf(o[this.props.optionValue]) >= 0); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for an else
after a return
Please, what about the Actualy, only one request is made to load possible values. If the user type text it only filter loaded values and not make aditionnal requests. It's the good behaviour @fzaninotto ? |
I don't know how |
Sorry, my question is not about |
The |
So, I think that we should remove |
Actually it's on |
Ah, I want to make And, later, I think we also support |
Yes, But |
Ah, sorry because I didn't understand what you mean... I will implement it soon. :D |
@DjLeChuck Done for |
@fzaninotto About map state, let me explain why I need 2 params:
But to make it display correctly, I must join them to a single param ( If we want to move to a reducer selector, we must find out better solution. What should I do for that? |
I have a strange behaviour and I don't know if it's my fault or not. <ReferenceManyInput label="Thèmes" source="themes" reference="themes" allowEmpty>
<SelectManyInput optionText="label" options={themesSelectStyle} />
</ReferenceManyInput>
|
With all the rebases and merges it was hard to keep track of the code, so I've squashed your commits (keeping you as the author) and started a new PR (#597) which I'll finish. |
Many thanks... :) |
I finished issue #45 . Please review.