Skip to content

Commit

Permalink
setting a number value now renders a real number input (#2091)
Browse files Browse the repository at this point in the history
- with min/max/step support
- closes #2083
- closes #1099
  • Loading branch information
foxriver76 authored Sep 2, 2023
1 parent f52cabb commit 11da853
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ The icons may not be reused in other projects without the proper flaticon licens
## Changelog
### **WORK IN PROGRESS**
* (foxriver76) fixed problem with discovery dialog
* (foxriver76) object browser now validates setting state of type number

### 6.9.2 (2023-09-01)
* (foxriver76) show info, if server time differs from client time
Expand Down
58 changes: 52 additions & 6 deletions src/src/components/Object/ObjectBrowserValue.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ class ObjectBrowserValue extends Component {
chartEnabled: (window._localStorage || window.localStorage).getItem('App.chartSetValue') !== 'false',
fullScreen: (window._localStorage || window.localStorage).getItem('App.fullScreen') === 'true',
targetValue: value,
/** IF input is invalid, set value button is disabled */
valid: true,
};

this.ack = false;
Expand All @@ -188,7 +190,7 @@ class ObjectBrowserValue extends Component {

this.inputRef = React.createRef();

this.chartFrom = Date.now() - 3600000 * 2;
this.chartFrom = Date.now() - 3_600_000 * 2;
}

componentDidMount() {
Expand All @@ -203,10 +205,21 @@ class ObjectBrowserValue extends Component {
}

setTimeout(() => {
if (this.inputRef && this.inputRef.current) {
if (this.inputRef?.current) {
const el = this.inputRef.current;
const value = el.value || '';
const origType = el.type;

// type number cannot be selected, so we perform a short workaround
if (el.type === 'number') {
el.type = 'text';
}

el.setSelectionRange(0, value.length);

if (origType === 'number') {
el.type = origType;
}
}
}, 200);
}
Expand Down Expand Up @@ -250,6 +263,33 @@ class ObjectBrowserValue extends Component {
});
}

/** @typedef {{ value: unknown, common: ioBroker.StateCommon }} NumberValidationOptions */

/**
* Check if a number value is valid according to the objects common properties
* @param {NumberValidationOptions} options value and common information
*
* @returns {boolean}
*/
isNumberValid(options) {
const { common } = options;
let { value } = options;

if (typeof value !== 'number') {
value = Number(value);
}

if (typeof common.min === 'number' && value < common.min) {
return false;
}

if (typeof common.max === 'number' && value > common.max) {
return false;
}

return true;
}

/**
* Render time picker component for date type
* @returns {React.JSX.Element}
Expand Down Expand Up @@ -489,7 +529,7 @@ class ObjectBrowserValue extends Component {
this.checkJsonError();
}

this.setState({ type: e.target.value });
this.setState({ type: e.target.value, valid: e.target.value === 'number' ? this.isNumberValid({ value: this.state.targetValue, common: this.props.object.common }) : true });
}}
>
<MenuItem value="string">String</MenuItem>
Expand Down Expand Up @@ -534,14 +574,19 @@ class ObjectBrowserValue extends Component {
variant="standard"
classes={{ root: this.props.classes.textInput }}
autoFocus
error={!this.state.valid}
type="number"
inputProps={{ step: this.props.object.common.step, min: this.props.object.common.min, max: this.props.object.common.max }}
inputRef={this.inputRef}
helperText={this.props.t(
'Press ENTER to write the value, when focused',
)}
value={parseFloat(this.state.targetValue) || 0}
value={this.state.targetValue.toString() || 0}
label={this.props.t('Value')}
onKeyUp={e => e.keyCode === 13 && this.onUpdate(e)}
onChange={e => this.setState({ targetValue: e.target.value })}
onKeyUp={e => e.keyCode === 13 && this.state.valid && this.onUpdate(e)}
onChange={e => {
this.setState({ targetValue: Number(e.target.value), valid: this.isNumberValid({ value: e.target.value, common: this.props.object.common }) });
}}
/> : (this.state.type === 'json' ?
this.renderJsonEditor()
: (this.state.type === 'states' ?
Expand Down Expand Up @@ -630,6 +675,7 @@ class ObjectBrowserValue extends Component {
{!this.props.expertMode ? <div style={{ flexGrow: 1 }} /> : null}
<Button
variant="contained"
disabled={!this.state.valid}
onClick={e => this.onUpdate(e)}
color="primary"
startIcon={<IconCheck />}
Expand Down

0 comments on commit 11da853

Please sign in to comment.