diff --git a/docs/de/nodes/widgets/ui-number-input.md b/docs/de/nodes/widgets/ui-number-input.md
index cf939070f..88d315288 100644
--- a/docs/de/nodes/widgets/ui-number-input.md
+++ b/docs/de/nodes/widgets/ui-number-input.md
@@ -99,6 +99,18 @@ Fügt Ihrem Dashboard eine einzelne Zahleneingabezeile hinzu.
+## Nachrichtenereignisse
+
+Sie können steuern, wann die Zahleneingabe Nachrichten sendet, indem Sie die folgenden Optionen im Knoteneditor unter "Nachricht senden bei:" konfigurieren:
+
+| Option | Beschreibung |
+|--------|--------------|
+| Bei Änderung | Sendet eine Nachricht, sobald sich der Wert im Eingabefeld ändert. |
+| Fokus verlassen | Sendet eine Nachricht, wenn das Eingabefeld den Fokus verliert (Benutzer klickt weg). |
+| Enter drücken | Sendet eine Nachricht, wenn der Benutzer die Enter-Taste drückt, während das Eingabefeld fokussiert ist. |
+
+Diese Optionen können unabhängig voneinander aktiviert oder deaktiviert werden, sodass Sie genau auswählen können, wann der Knoten Nachrichten senden soll.
+
## Beispiel
{data-zoomable}
diff --git a/docs/en/nodes/widgets/ui-number-input.md b/docs/en/nodes/widgets/ui-number-input.md
index bf112cf4b..bb0f420b8 100644
--- a/docs/en/nodes/widgets/ui-number-input.md
+++ b/docs/en/nodes/widgets/ui-number-input.md
@@ -99,6 +99,18 @@ Adds a single number input row to your dashboard.
+## Message Events
+
+You can control when the number input emits messages by configuring the following options in the node editor under "Send message on:":
+
+| Option | Description |
+|--------|-------------|
+| On Change | Sends a message each time the value changes in the input field. |
+| Focus Leave | Sends a message when the input field loses focus (user clicks away). |
+| Press Enter | Sends a message when the user presses the Enter key while the input is focused. |
+
+These options can be enabled or disabled independently, allowing you to choose exactly when the node should emit messages.
+
## Example
{data-zoomable}
diff --git a/nodes/config/ui_base.js b/nodes/config/ui_base.js
index 028125d68..aeae52702 100644
--- a/nodes/config/ui_base.js
+++ b/nodes/config/ui_base.js
@@ -658,9 +658,10 @@ module.exports = function (RED) {
* @param {Socket} conn - socket.io socket connecting to the server
* @param {String} id - widget id sending the action
* @param {*} value - The value to send to node-red. Typically this is the payload
+ * @param {String} event - The event type (onChange, focusLeave, pressEnter)
* @returns void
*/
- async function onChange (conn, id, value) {
+ async function onChange (conn, id, value, event) {
// console.log('conn:' + conn.id, 'on:widget-change:' + id, value)
// get widget node and configuration
@@ -684,13 +685,18 @@ module.exports = function (RED) {
msg = addConnectionCredentials(RED, msg, conn, n)
- async function defaultHandler (msg, value, conn, id) {
+ async function defaultHandler (msg, value, conn, id, event) {
if (typeof (value) === 'object' && value !== null && hasProperty(value, 'payload')) {
msg.payload = value.payload
} else {
msg.payload = value
}
+ // Add event field if provided
+ if (event) {
+ msg.event = event
+ }
+
msg = await appendTopic(RED, widgetConfig, wNode, msg)
if (widgetEvents?.beforeSend) {
@@ -707,7 +713,7 @@ module.exports = function (RED) {
// Most of the time, we can just use this default handler,
// but sometimes a node needs to do something specific (e.g. ui-switch)
const handler = typeof (widgetEvents.onChange) === 'function' ? widgetEvents.onChange : defaultHandler
- await handler(msg, value, conn, id)
+ await handler(msg, value, conn, id, event)
} catch (error) {
console.log(error)
let errorHandler = typeof (widgetEvents.onError) === 'function' ? widgetEvents.onError : null
diff --git a/nodes/widgets/locales/de/ui_number_input.json b/nodes/widgets/locales/de/ui_number_input.json
index 8f166c212..98d96e612 100644
--- a/nodes/widgets/locales/de/ui_number_input.json
+++ b/nodes/widgets/locales/de/ui_number_input.json
@@ -15,6 +15,7 @@
"passThrough": "Wenn msg am Eingang ankommt, an den Ausgang weiterleiten:",
"clearable": "Zahleneingabe mit Schaltfläche löschen",
"sendMessageOn": "Nachricht senden bei:",
+ "onChange": "Bei Änderung",
"focusLeave": "Fokus verlassen",
"pressEnter": "Enter drücken",
"whenChanged": "Bei Änderung senden:",
diff --git a/nodes/widgets/locales/en-US/ui_number_input.json b/nodes/widgets/locales/en-US/ui_number_input.json
index 6d325f5a3..5000e8bad 100644
--- a/nodes/widgets/locales/en-US/ui_number_input.json
+++ b/nodes/widgets/locales/en-US/ui_number_input.json
@@ -15,6 +15,7 @@
"passThrough": "If msg arrives on input, pass through to output:",
"clearable": "Clear number input with button",
"sendMessageOn": "Send message on:",
+ "onChange": "On Change",
"focusLeave": "Focus Leave",
"pressEnter": "Press Enter",
"whenChanged": "When changed, send:",
diff --git a/nodes/widgets/ui_number_input.html b/nodes/widgets/ui_number_input.html
index 9523b347b..c13b135fd 100644
--- a/nodes/widgets/ui_number_input.html
+++ b/nodes/widgets/ui_number_input.html
@@ -37,6 +37,7 @@
},
tooltip: { value: '' },
passthru: { value: true },
+ sendOnChange: { value: true },
sendOnBlur: { value: true },
sendOnEnter: { value: true },
className: { value: '' },
@@ -101,6 +102,9 @@
if (this.sendOnClear === undefined) {
$('#node-input-sendOnClear').prop('checked', false)
}
+ if (this.sendOnChange === undefined) {
+ $('#node-input-sendOnChange').prop('checked', true)
+ }
if (!this.iconPosition) {
$('#node-input-iconPosition').val('left')
@@ -217,6 +221,10 @@
+
+
+
+
diff --git a/ui/src/widgets/ui-number-input/UINumberInput.vue b/ui/src/widgets/ui-number-input/UINumberInput.vue
index c81170fd2..23ed2692d 100644
--- a/ui/src/widgets/ui-number-input/UINumberInput.vue
+++ b/ui/src/widgets/ui-number-input/UINumberInput.vue
@@ -150,7 +150,7 @@ export default {
} else if (this.value > this.max) {
this.value = this.max
}
- this.send()
+ this.send('onChange')
this.previousValue = this.value
}
}
@@ -175,26 +175,28 @@ export default {
this.$dataTracker(this.id, null, null, this.onDynamicProperties, null)
},
methods: {
- send () {
- this.$socket.emit('widget-change', this.id, this.value)
+ send (event) {
+ this.$socket.emit('widget-change', this.id, this.value, event)
},
onChange () {
- this.send()
+ if (this.props.sendOnChange) {
+ this.send('onChange')
+ }
},
onBlur: function () {
if (this.props.sendOnBlur) {
// user has to click away (focus out / blur) they want it submitted
- this.send()
+ this.send('focusLeave')
}
},
onEnter: function () {
if (this.props.sendOnEnter) {
// user has to press they want it submitted
- this.send()
+ this.send('pressEnter')
}
},
onClear () {
- this.send()
+ this.send('onChange')
},
makeMdiIcon (icon) {
return 'mdi-' + icon?.replace(/^mdi-/, '')