Change MultiDataEntry to FC with hooks
This commit is contained in:
parent
efb660db9e
commit
6ecd5b6819
@ -1,4 +1,4 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import './multi-data-entry.css';
|
||||
|
||||
@ -6,94 +6,66 @@ import { BaseDataEntryProps } from '../data-entry';
|
||||
import { DataEntryInput, TextDataEntryInputProps } from '../data-entry-input';
|
||||
import { DataTitleCopyable } from '../data-title';
|
||||
|
||||
|
||||
interface MultiDataEntryProps extends BaseDataEntryProps, TextDataEntryInputProps {
|
||||
value: string[];
|
||||
copyable: boolean;
|
||||
editableEntries: boolean;
|
||||
confirmOnEnter: boolean;
|
||||
|
||||
addOnAutofillSelect: boolean;
|
||||
acceptAutofillValuesOnly: boolean;
|
||||
copyable?: boolean;
|
||||
editableEntries?: boolean;
|
||||
confirmOnEnter?: boolean;
|
||||
}
|
||||
|
||||
interface MultiDataEntryState {
|
||||
newValue: string;
|
||||
}
|
||||
export const MultiDataEntry: React.FC<MultiDataEntryProps> = ({
|
||||
editableEntries = false,
|
||||
copyable = false,
|
||||
confirmOnEnter = true,
|
||||
...props
|
||||
}) => {
|
||||
const [newValue, setNewValue] = useState<string>();
|
||||
|
||||
class MultiDataEntry extends Component<MultiDataEntryProps, MultiDataEntryState> {
|
||||
const values = useMemo(() => props.value ?? [], [props.value]);
|
||||
|
||||
static defaultProps = {
|
||||
editableEntries: false,
|
||||
copyable: false,
|
||||
confirmOnEnter: true,
|
||||
addOnAutofillSelect: false,
|
||||
acceptAutofillValuesOnly: false
|
||||
};
|
||||
const edit = useCallback((index: number, value: string) => {
|
||||
const editedValues = values.slice();
|
||||
editedValues.splice(index, 1, value);
|
||||
props.onChange(props.slug, editedValues);
|
||||
}, [values, props.onChange, props.slug]);
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
newValue: null
|
||||
};
|
||||
|
||||
this.setNewValue = this.setNewValue.bind(this);
|
||||
this.edit = this.edit.bind(this);
|
||||
this.addNew = this.addNew.bind(this);
|
||||
this.remove = this.remove.bind(this);
|
||||
}
|
||||
/* accept a newValue parameter to handle cases where the value is set and submitted at the same time
|
||||
* (like with autofill select enabled) - but otherwise use the current newValue saved in state
|
||||
*/
|
||||
const addNew = useCallback((newValueArg?: string) => {
|
||||
const val = newValueArg ?? newValue;
|
||||
if(val == undefined) return;
|
||||
|
||||
getValues() {
|
||||
return this.props.value == undefined ? [] : this.props.value;
|
||||
}
|
||||
const editedValues = values.slice().concat(val);
|
||||
|
||||
cloneValues() {
|
||||
return this.getValues().slice();
|
||||
}
|
||||
setNewValue(null);
|
||||
props.onChange(props.slug, editedValues);
|
||||
}, [newValue, values, props.onChange, props.slug]);
|
||||
|
||||
setNewValue(value: string) {
|
||||
this.setState({newValue: value});
|
||||
}
|
||||
|
||||
edit(index: number, value: string) {
|
||||
let values = this.cloneValues();
|
||||
values.splice(index, 1, value);
|
||||
this.props.onChange(this.props.slug, values);
|
||||
}
|
||||
addNew(newValue?: string) {
|
||||
// accept a newValue parameter to handle cases where the value is set and submitted at the same time
|
||||
// (like with autofill select enabled) - but otherwise use the current newValue saved in state
|
||||
const val = newValue ?? this.state.newValue;
|
||||
if (val == undefined) return;
|
||||
const values = this.cloneValues().concat(val);
|
||||
this.setState({newValue: null});
|
||||
this.props.onChange(this.props.slug, values);
|
||||
}
|
||||
const remove = useCallback((index: number) => {
|
||||
const editedValues = values.slice();
|
||||
editedValues.splice(index, 1);
|
||||
|
||||
remove(index: number){
|
||||
const values = this.cloneValues();
|
||||
values.splice(index, 1);
|
||||
this.props.onChange(this.props.slug, values);
|
||||
}
|
||||
props.onChange(props.slug, editedValues);
|
||||
}, [values, props.onChange, props.slug]);
|
||||
|
||||
render() {
|
||||
const values = this.getValues();
|
||||
const props = this.props;
|
||||
const isEditing = props.mode === 'edit';
|
||||
const isDisabled = !isEditing || props.disabled;
|
||||
const slugWithModifier = props.slug + (props.slugModifier ?? '');
|
||||
|
||||
return <Fragment>
|
||||
<DataTitleCopyable
|
||||
slug={props.slug}
|
||||
slugModifier={props.slugModifier}
|
||||
title={props.title}
|
||||
tooltip={props.tooltip}
|
||||
disabled={props.disabled || props.value == undefined || props.value.length === 0}
|
||||
copy={props.copyable ? props.copy : undefined}
|
||||
/>
|
||||
<div id={`${props.slug}-wrapper`}>
|
||||
<ul className="data-link-list">
|
||||
const isEditing = props.mode === 'edit';
|
||||
const isDisabled = !isEditing || props.disabled;
|
||||
const slugWithModifier = props.slug + (props.slugModifier ?? '');
|
||||
|
||||
return (<>
|
||||
<DataTitleCopyable
|
||||
slug={props.slug}
|
||||
slugModifier={props.slugModifier}
|
||||
title={props.title}
|
||||
tooltip={props.tooltip}
|
||||
disabled={props.disabled || props.value == undefined || props.value.length === 0}
|
||||
copy={copyable ? props.copy : undefined}
|
||||
/>
|
||||
<div id={`${props.slug}-wrapper`}>
|
||||
<ul className="data-link-list">
|
||||
{
|
||||
values.length === 0 && !isEditing &&
|
||||
<div className="input-group">
|
||||
@ -108,8 +80,8 @@ class MultiDataEntry extends Component<MultiDataEntryProps, MultiDataEntryState>
|
||||
name={`${slugWithModifier}-${i}`}
|
||||
id={`${slugWithModifier}-${i}`}
|
||||
value={val}
|
||||
disabled={!props.editableEntries || isDisabled}
|
||||
onChange={(key, val) => this.edit(i, val)}
|
||||
disabled={!editableEntries || isDisabled}
|
||||
onChange={(_key, val) => edit(i, val)}
|
||||
|
||||
maxLength={props.maxLength}
|
||||
isUrl={props.isUrl}
|
||||
@ -121,7 +93,7 @@ class MultiDataEntry extends Component<MultiDataEntryProps, MultiDataEntryState>
|
||||
{
|
||||
!isDisabled &&
|
||||
<div className="input-group-append">
|
||||
<button type="button" onClick={e => this.remove(i)}
|
||||
<button type="button" onClick={() => remove(i)}
|
||||
title="Remove"
|
||||
data-index={i} className="btn btn-outline-dark">✕</button>
|
||||
</div>
|
||||
@ -129,25 +101,25 @@ class MultiDataEntry extends Component<MultiDataEntryProps, MultiDataEntryState>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
{
|
||||
!isDisabled &&
|
||||
</ul>
|
||||
{
|
||||
!isDisabled &&
|
||||
<div className="input-group">
|
||||
<DataEntryInput
|
||||
slug={props.slug}
|
||||
name={slugWithModifier}
|
||||
id={slugWithModifier}
|
||||
value={this.state.newValue}
|
||||
value={newValue}
|
||||
disabled={props.disabled}
|
||||
required={props.required && values.length < 1}
|
||||
onChange={(key, val) => this.setNewValue(val)}
|
||||
onConfirm={(key, val) => this.addNew(val)}
|
||||
onChange={(_key, val) => setNewValue(val)}
|
||||
onConfirm={(_key, val) => addNew(val)}
|
||||
|
||||
maxLength={props.maxLength}
|
||||
placeholder={props.placeholder}
|
||||
isUrl={props.isUrl}
|
||||
valueTransform={props.valueTransform}
|
||||
confirmOnEnter={props.confirmOnEnter}
|
||||
confirmOnEnter={confirmOnEnter}
|
||||
|
||||
autofill={props.autofill}
|
||||
showAllOptionsOnEmpty={props.showAllOptionsOnEmpty}
|
||||
@ -157,15 +129,12 @@ class MultiDataEntry extends Component<MultiDataEntryProps, MultiDataEntryState>
|
||||
<button type="button"
|
||||
className="btn btn-outline-dark"
|
||||
title="Add to list"
|
||||
onClick={() => this.addNew()}
|
||||
disabled={this.state.newValue == undefined}
|
||||
onClick={() => addNew()}
|
||||
disabled={newValue == undefined}
|
||||
>+</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Fragment>;
|
||||
}
|
||||
}
|
||||
|
||||
export default MultiDataEntry;
|
||||
}
|
||||
</div>
|
||||
</>)
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { dataFields } from '../../config/data-fields-config';
|
||||
import MultiDataEntry from '../data-components/multi-data-entry/multi-data-entry';
|
||||
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
|
||||
import NumericDataEntry from '../data-components/numeric-data-entry';
|
||||
import SelectDataEntry from '../data-components/select-data-entry';
|
||||
import TextboxDataEntry from '../data-components/textbox-data-entry';
|
||||
|
@ -6,7 +6,7 @@ import { FieldRow } from '../../data-components/field-row';
|
||||
import DataEntry, { BaseDataEntryProps } from '../../data-components/data-entry';
|
||||
import { dataFields } from '../../../config/data-fields-config';
|
||||
import SelectDataEntry from '../../data-components/select-data-entry';
|
||||
import MultiDataEntry from '../../data-components/multi-data-entry/multi-data-entry';
|
||||
import { MultiDataEntry } from '../../data-components/multi-data-entry/multi-data-entry';
|
||||
import { NumberRangeDataEntry } from './number-range-data-entry';
|
||||
|
||||
import './dynamics-data-entry.css';
|
||||
|
@ -3,7 +3,7 @@ import React, { Fragment } from 'react';
|
||||
import InfoBox from '../../components/info-box';
|
||||
import { dataFields } from '../../config/data-fields-config';
|
||||
import DataEntry from '../data-components/data-entry';
|
||||
import MultiDataEntry from '../data-components/multi-data-entry/multi-data-entry';
|
||||
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
|
||||
import withCopyEdit from '../data-container';
|
||||
|
||||
import { CategoryViewProps } from './category-view-props';
|
||||
@ -28,7 +28,6 @@ const UseView: React.FunctionComponent<CategoryViewProps> = (props) => (
|
||||
copyable={true}
|
||||
autofill={true}
|
||||
showAllOptionsOnEmpty={true}
|
||||
addOnAutofillSelect={true}
|
||||
/>
|
||||
<Verification
|
||||
slug="current_landuse_group"
|
||||
|
Loading…
Reference in New Issue
Block a user