Integer and Numeric inputs fixes.
parent
73e1cbc0b9
commit
af27af8d42
|
@ -34,28 +34,6 @@ function MappedFormControlBase({type, value, id, onChange, className, visible, i
|
||||||
onChange && onChange(value);
|
onChange && onChange(value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onIntChange = useCallback((e) => {
|
|
||||||
let value = e;
|
|
||||||
if(e && e.target) {
|
|
||||||
value = e.target.value;
|
|
||||||
}
|
|
||||||
if(!isNaN(parseInt(value))) {
|
|
||||||
value = parseInt(value);
|
|
||||||
}
|
|
||||||
onChange && onChange(value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onNumChange = useCallback((e) => {
|
|
||||||
let value = e;
|
|
||||||
if(e && e.target) {
|
|
||||||
value = e.target.value;
|
|
||||||
}
|
|
||||||
if(!isNaN(parseFloat(value))) {
|
|
||||||
value = parseFloat(value);
|
|
||||||
}
|
|
||||||
onChange && onChange(value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if(!visible) {
|
if(!visible) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
@ -63,9 +41,9 @@ function MappedFormControlBase({type, value, id, onChange, className, visible, i
|
||||||
/* The mapping uses Form* components as it comes with labels */
|
/* The mapping uses Form* components as it comes with labels */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'int':
|
case 'int':
|
||||||
return <FormInputText name={name} value={value} onChange={onIntChange} className={className} inputRef={inputRef} {...props}/>;
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='int'/>;
|
||||||
case 'numeric':
|
case 'numeric':
|
||||||
return <FormInputText name={name} value={value} onChange={onNumChange} className={className} inputRef={inputRef} {...props}/>;
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='numeric'/>;
|
||||||
case 'text':
|
case 'text':
|
||||||
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props}/>;
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props}/>;
|
||||||
case 'multiline':
|
case 'multiline':
|
||||||
|
@ -131,28 +109,6 @@ function MappedCellControlBase({cell, value, id, optionsLoaded, onCellChange, vi
|
||||||
onCellChange && onCellChange(value);
|
onCellChange && onCellChange(value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onIntChange = useCallback((e) => {
|
|
||||||
let value = e;
|
|
||||||
if(e && e.target) {
|
|
||||||
value = e.target.value;
|
|
||||||
}
|
|
||||||
if(!isNaN(parseInt(value))) {
|
|
||||||
value = parseInt(value);
|
|
||||||
}
|
|
||||||
onCellChange && onCellChange(value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onNumChange = useCallback((e) => {
|
|
||||||
let value = e;
|
|
||||||
if(e && e.target) {
|
|
||||||
value = e.target.value;
|
|
||||||
}
|
|
||||||
if(!isNaN(parseFloat(value))) {
|
|
||||||
value = parseFloat(value);
|
|
||||||
}
|
|
||||||
onCellChange && onCellChange(value);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/* Some grid cells are based on options selected in other cells.
|
/* Some grid cells are based on options selected in other cells.
|
||||||
* lets trigger a re-render for the row if optionsLoaded
|
* lets trigger a re-render for the row if optionsLoaded
|
||||||
*/
|
*/
|
||||||
|
@ -169,9 +125,9 @@ function MappedCellControlBase({cell, value, id, optionsLoaded, onCellChange, vi
|
||||||
/* The mapping does not need Form* components as labels are not needed for grid cells */
|
/* The mapping does not need Form* components as labels are not needed for grid cells */
|
||||||
switch(cell) {
|
switch(cell) {
|
||||||
case 'int':
|
case 'int':
|
||||||
return <InputText name={name} value={value} onChange={onIntChange} {...props}/>;
|
return <InputText name={name} value={value} onChange={onTextChange} {...props} type='int'/>;
|
||||||
case 'numeric':
|
case 'numeric':
|
||||||
return <InputText name={name} value={value} onChange={onNumChange} {...props}/>;
|
return <InputText name={name} value={value} onChange={onTextChange} {...props} type='numeric'/>;
|
||||||
case 'text':
|
case 'text':
|
||||||
return <InputText name={name} value={value} onChange={onTextChange} {...props}/>;
|
return <InputText name={name} value={value} onChange={onTextChange} {...props}/>;
|
||||||
case 'password':
|
case 'password':
|
||||||
|
|
|
@ -291,11 +291,22 @@ FormInputDateTimePicker.propTypes = {
|
||||||
|
|
||||||
/* Use forwardRef to pass ref prop to OutlinedInput */
|
/* Use forwardRef to pass ref prop to OutlinedInput */
|
||||||
export const InputText = forwardRef(({
|
export const InputText = forwardRef(({
|
||||||
cid, helpid, readonly, disabled, maxlength=255, value, onChange, controlProps, ...props}, ref)=>{
|
cid, helpid, readonly, disabled, maxlength=255, value, onChange, controlProps, type, ...props}, ref)=>{
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const patterns = {
|
||||||
|
'numeric': '^-?[0-9]\\d*\\.?\\d*$',
|
||||||
|
'int': '^-?[0-9]\\d*$',
|
||||||
|
};
|
||||||
|
let onChangeFinal = (e)=>{
|
||||||
|
let changeVal = e.target.value;
|
||||||
|
|
||||||
let onChangeFinal = (changeVal)=>{
|
/* For type number, we set type as tel with number regex to get validity.*/
|
||||||
|
if(['numeric', 'int'].indexOf(type) > -1) {
|
||||||
|
if(!e.target.validity.valid && changeVal !== '' && changeVal !== '-') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(controlProps?.formatter) {
|
if(controlProps?.formatter) {
|
||||||
changeVal = controlProps.formatter.toRaw(changeVal);
|
changeVal = controlProps.formatter.toRaw(changeVal);
|
||||||
}
|
}
|
||||||
|
@ -317,6 +328,7 @@ export const InputText = forwardRef(({
|
||||||
id: cid,
|
id: cid,
|
||||||
maxLength: maxlength,
|
maxLength: maxlength,
|
||||||
'aria-describedby': helpid,
|
'aria-describedby': helpid,
|
||||||
|
...(type ? {pattern: patterns[type]} : {})
|
||||||
}}
|
}}
|
||||||
readOnly={Boolean(readonly)}
|
readOnly={Boolean(readonly)}
|
||||||
disabled={Boolean(disabled)}
|
disabled={Boolean(disabled)}
|
||||||
|
@ -326,6 +338,7 @@ export const InputText = forwardRef(({
|
||||||
onChange={onChangeFinal}
|
onChange={onChangeFinal}
|
||||||
{...controlProps}
|
{...controlProps}
|
||||||
{...props}
|
{...props}
|
||||||
|
{...(['numeric', 'int'].indexOf(type) > -1 ? {type: 'tel'} : {})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -340,6 +353,7 @@ InputText.propTypes = {
|
||||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
controlProps: PropTypes.object,
|
controlProps: PropTypes.object,
|
||||||
|
type: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function FormInputText({hasError, required, label, className, helpMessage, testcid, ...props}) {
|
export function FormInputText({hasError, required, label, className, helpMessage, testcid, ...props}) {
|
||||||
|
|
|
@ -43,6 +43,16 @@ function getSchemaAllTypes() {
|
||||||
|
|
||||||
describe('SchemaView', ()=>{
|
describe('SchemaView', ()=>{
|
||||||
let mount;
|
let mount;
|
||||||
|
let numberChangeEvent = (value)=>{
|
||||||
|
return {
|
||||||
|
target: {
|
||||||
|
value: value,
|
||||||
|
validity: {
|
||||||
|
valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/* Use createMount so that material ui components gets the required context */
|
/* Use createMount so that material ui components gets the required context */
|
||||||
/* https://material-ui.com/guides/testing/#api */
|
/* https://material-ui.com/guides/testing/#api */
|
||||||
|
@ -91,7 +101,7 @@ describe('SchemaView', ()=>{
|
||||||
},
|
},
|
||||||
simulateValidData = ()=>{
|
simulateValidData = ()=>{
|
||||||
ctrl.find('MappedFormControl[id="field1"]').find('input').simulate('change', {target: {value: 'val1'}});
|
ctrl.find('MappedFormControl[id="field1"]').find('input').simulate('change', {target: {value: 'val1'}});
|
||||||
ctrl.find('MappedFormControl[id="field2"]').find('input').simulate('change', {target: {value: '2'}});
|
ctrl.find('MappedFormControl[id="field2"]').find('input').simulate('change', numberChangeEvent('2'));
|
||||||
ctrl.find('MappedFormControl[id="field5"]').find('textarea').simulate('change', {target: {value: 'val5'}});
|
ctrl.find('MappedFormControl[id="field5"]').find('textarea').simulate('change', {target: {value: 'val5'}});
|
||||||
/* Add a row */
|
/* Add a row */
|
||||||
ctrl.find('DataGridView').find('PgIconButton[data-test="add-row"]').find('button').simulate('click');
|
ctrl.find('DataGridView').find('PgIconButton[data-test="add-row"]').find('button').simulate('click');
|
||||||
|
@ -117,7 +127,7 @@ describe('SchemaView', ()=>{
|
||||||
});
|
});
|
||||||
|
|
||||||
it('change text', (done)=>{
|
it('change text', (done)=>{
|
||||||
ctrl.find('MappedFormControl[id="field2"]').find('input').simulate('change', {target: {value: '2'}});
|
ctrl.find('MappedFormControl[id="field2"]').find('input').simulate('change', numberChangeEvent('2'));
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
ctrl.update();
|
ctrl.update();
|
||||||
/* Error should come for field1 as it is empty and noEmpty true */
|
/* Error should come for field1 as it is empty and noEmpty true */
|
||||||
|
@ -210,7 +220,7 @@ describe('SchemaView', ()=>{
|
||||||
});
|
});
|
||||||
|
|
||||||
it('data invalid', (done)=>{
|
it('data invalid', (done)=>{
|
||||||
ctrl.find('MappedFormControl[id="field2"]').find('input').simulate('change', {target: {value: '2'}});
|
ctrl.find('MappedFormControl[id="field2"]').find('input').simulate('change', numberChangeEvent('2'));
|
||||||
ctrl.find('ForwardRef(Tab)[label="SQL"]').find('button').simulate('click');
|
ctrl.find('ForwardRef(Tab)[label="SQL"]').find('button').simulate('click');
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
ctrl.update();
|
ctrl.update();
|
||||||
|
@ -240,7 +250,7 @@ describe('SchemaView', ()=>{
|
||||||
expect(onSave.calls.argsFor(0)[1]).toEqual({
|
expect(onSave.calls.argsFor(0)[1]).toEqual({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
field1: 'val1',
|
field1: 'val1',
|
||||||
field2: 2,
|
field2: '2',
|
||||||
field5: 'val5',
|
field5: 'val5',
|
||||||
fieldcoll: [
|
fieldcoll: [
|
||||||
{field3: null, field4: null, field5: 'rval51'},
|
{field3: null, field4: null, field5: 'rval51'},
|
||||||
|
|
Loading…
Reference in New Issue