fix: list widget validation after sort (#3611)

This commit is contained in:
Bartholomew 2020-04-19 09:46:26 +01:00 committed by GitHub
parent 72b26f4435
commit 3d0856ea88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -107,11 +107,12 @@ export default class ListControl extends React.Component {
const { field, value } = props; const { field, value } = props;
const allItemsCollapsed = field.get('collapsed', true); const allItemsCollapsed = field.get('collapsed', true);
const itemsCollapsed = value && Array(value.size).fill(allItemsCollapsed); const itemsCollapsed = value && Array(value.size).fill(allItemsCollapsed);
const keys = value && Array.from({ length: value.size }, () => uuid());
this.state = { this.state = {
itemsCollapsed: List(itemsCollapsed), itemsCollapsed: List(itemsCollapsed),
value: valueToString(value), value: valueToString(value),
keys: List(), keys: List(keys),
}; };
} }
@ -172,7 +173,10 @@ export default class ListControl extends React.Component {
this.getValueType() === valueTypes.SINGLE this.getValueType() === valueTypes.SINGLE
? this.singleDefault() ? this.singleDefault()
: fromJS(this.multipleDefault(field.get('fields'))); : fromJS(this.multipleDefault(field.get('fields')));
this.setState({ itemsCollapsed: this.state.itemsCollapsed.push(false) }); this.setState({
itemsCollapsed: this.state.itemsCollapsed.push(false),
keys: this.state.keys.push(uuid()),
});
onChange((value || List()).push(parsedValue)); onChange((value || List()).push(parsedValue));
}; };
@ -187,7 +191,10 @@ export default class ListControl extends React.Component {
handleAddType = (type, typeKey) => { handleAddType = (type, typeKey) => {
const { value, onChange } = this.props; const { value, onChange } = this.props;
const parsedValue = fromJS(this.mixedDefault(typeKey, type)); const parsedValue = fromJS(this.mixedDefault(typeKey, type));
this.setState({ itemsCollapsed: this.state.itemsCollapsed.push(false) }); this.setState({
itemsCollapsed: this.state.itemsCollapsed.push(false),
keys: this.state.keys.push(uuid()),
});
onChange((value || List()).push(parsedValue)); onChange((value || List()).push(parsedValue));
}; };
@ -227,13 +234,17 @@ export default class ListControl extends React.Component {
processControlRef = ref => { processControlRef = ref => {
if (!ref) return; if (!ref) return;
this.validations.push(ref.validate); const {
validate,
props: { validationKey: key },
} = ref;
this.validations.push({ key, validate });
}; };
validate = () => { validate = () => {
if (this.getValueType()) { if (this.getValueType()) {
this.validations.forEach(validateListItem => { this.validations.forEach(item => {
validateListItem(); item.validate();
}); });
} else { } else {
this.props.validate(); this.props.validate();
@ -265,12 +276,13 @@ export default class ListControl extends React.Component {
}; };
} }
handleRemove = (index, event) => { handleRemove = (index, key, event) => {
event.preventDefault(); event.preventDefault();
const { itemsCollapsed } = this.state; const { itemsCollapsed, keys } = this.state;
const { value, metadata, onChange, field, clearFieldErrors } = this.props; const { value, metadata, onChange, field, clearFieldErrors } = this.props;
const collectionName = field.get('name'); const collectionName = field.get('name');
const isSingleField = this.getValueType() === valueTypes.SINGLE; const isSingleField = this.getValueType() === valueTypes.SINGLE;
const validations = this.validations;
const metadataRemovePath = isSingleField ? value.get(index) : value.get(index).valueSeq(); const metadataRemovePath = isSingleField ? value.get(index) : value.get(index).valueSeq();
const parsedMetadata = const parsedMetadata =
@ -278,17 +290,14 @@ export default class ListControl extends React.Component {
? { [collectionName]: metadata.removeIn(metadataRemovePath) } ? { [collectionName]: metadata.removeIn(metadataRemovePath) }
: metadata; : metadata;
// Removed item object index is the last item in the list this.setState({ itemsCollapsed: itemsCollapsed.delete(index), keys: keys.delete(index) });
const removedItemIndex = value.count() - 1;
this.setState({ itemsCollapsed: itemsCollapsed.delete(index) });
onChange(value.remove(index), parsedMetadata); onChange(value.remove(index), parsedMetadata);
clearFieldErrors(); clearFieldErrors();
// Remove deleted item object validation // Remove deleted item object validation
if (this.validations) { if (validations) {
this.validations.splice(removedItemIndex, 1); this.validations = validations.filter(item => item.key !== key);
} }
}; };
@ -322,7 +331,7 @@ export default class ListControl extends React.Component {
} }
onSortEnd = ({ oldIndex, newIndex }) => { onSortEnd = ({ oldIndex, newIndex }) => {
const { value } = this.props; const { value, clearFieldErrors } = this.props;
const { itemsCollapsed, keys } = this.state; const { itemsCollapsed, keys } = this.state;
// Update value // Update value
@ -337,6 +346,10 @@ export default class ListControl extends React.Component {
// Reset item to ensure updated state // Reset item to ensure updated state
const updatedKeys = keys.set(oldIndex, uuid()).set(newIndex, uuid()); const updatedKeys = keys.set(oldIndex, uuid()).set(newIndex, uuid());
this.setState({ itemsCollapsed: updatedItemsCollapsed, keys: updatedKeys }); this.setState({ itemsCollapsed: updatedItemsCollapsed, keys: updatedKeys });
//clear error fields and remove old validations
clearFieldErrors();
this.validations = this.validations.filter(item => updatedKeys.includes(item.key));
}; };
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
@ -354,7 +367,7 @@ export default class ListControl extends React.Component {
const { itemsCollapsed, keys } = this.state; const { itemsCollapsed, keys } = this.state;
const collapsed = itemsCollapsed.get(index); const collapsed = itemsCollapsed.get(index);
const key = keys.get(index) || `item-${index}`; const key = keys.get(index);
let field = this.props.field; let field = this.props.field;
if (this.getValueType() === valueTypes.MIXED) { if (this.getValueType() === valueTypes.MIXED) {
@ -373,7 +386,7 @@ export default class ListControl extends React.Component {
<StyledListItemTopBar <StyledListItemTopBar
collapsed={collapsed} collapsed={collapsed}
onCollapseToggle={partial(this.handleItemCollapseToggle, index)} onCollapseToggle={partial(this.handleItemCollapseToggle, index)}
onRemove={partial(this.handleRemove, index)} onRemove={partial(this.handleRemove, index, key)}
dragHandleHOC={SortableHandle} dragHandleHOC={SortableHandle}
/> />
<NestedObjectLabel collapsed={collapsed}>{this.objectLabel(item)}</NestedObjectLabel> <NestedObjectLabel collapsed={collapsed}>{this.objectLabel(item)}</NestedObjectLabel>
@ -397,6 +410,7 @@ export default class ListControl extends React.Component {
fieldsErrors={fieldsErrors} fieldsErrors={fieldsErrors}
ref={this.processControlRef} ref={this.processControlRef}
controlRef={controlRef} controlRef={controlRef}
validationKey={key}
/> />
)} )}
</ClassNames> </ClassNames>
@ -407,15 +421,16 @@ export default class ListControl extends React.Component {
renderErroneousTypedItem(index, item) { renderErroneousTypedItem(index, item) {
const field = this.props.field; const field = this.props.field;
const errorMessage = getErrorMessageForTypedFieldAndValue(field, item); const errorMessage = getErrorMessageForTypedFieldAndValue(field, item);
const key = `item-${index}`;
return ( return (
<SortableListItem <SortableListItem
css={[styles.listControlItem, styles.listControlItemCollapsed]} css={[styles.listControlItem, styles.listControlItemCollapsed]}
index={index} index={index}
key={`item-${index}`} key={key}
> >
<StyledListItemTopBar <StyledListItemTopBar
onCollapseToggle={null} onCollapseToggle={null}
onRemove={partial(this.handleRemove, index)} onRemove={partial(this.handleRemove, index, key)}
dragHandleHOC={SortableHandle} dragHandleHOC={SortableHandle}
/> />
<NestedObjectLabel collapsed={true} error={true}> <NestedObjectLabel collapsed={true} error={true}>