Dashboard OnClick: click events for Dashboard 2.0 widgets

A community template node for Node-RED Dashboard 2.0 (not an official FlowFuse add-on) that makes widgets report clicks. The Dashboard 2.0 widgets have no click event of their own, so this adds one. It works with most of the widgets. See Tested below.

What it does

  • It lets you configure a widget to be clickable by editing the Class field of a Dashboard 2.0 widget. Add a class that starts with gid-, for example gid-fridge.
  • When a widget with such a class is clicked, a message goes out of the template node:
    • msg.payload is the id (fridge)
    • msg.topic is the widget type plus _click (gauge_click, text_click, chart_click and so on)
    • msg.nodeId is the Node-RED node id of the widget
  • Clickable widgets get a hand cursor and a brief flash when clicked. The flash can be switched off.
  • Widgets without a gid- class do nothing and keep their normal cursor.
  • It is a single ui-template with its Type set to Widget (UI-Scoped), so one copy covers every page of the dashboard and takes no room in the layout.

How to use it

  1. Import the flow, open the Dashboard OnClick template node and select your dashboard in the UI field.
  2. Put gid- followed by a name in the Class field of each widget you want to click, for example gid-fridge.
  3. Deploy, then reload the dashboard page with Ctrl+F5.
  4. Click a widget and watch the debug sidebar.

Dashboard 2.0 version 1.33.0 tested widgets

  • ui-button
  • ui-button-group
  • ui-chart
  • ui-dropdown
  • ui-file-input
  • ui-form
  • ui-gauge
  • ui-markdown
  • ui-number-input
  • ui-progress
  • ui-slider
  • ui-switch
  • ui-table
  • ui-template
  • ui-text
  • ui-text-field
  • ui-text-input

Limitations

  • It relies on Dashboard 2.0's own CSS class names (nrdb-ui-widget and the type class next to it). A future Dashboard update could change those and break it.
  • After editing the template, reload the dashboard page (Ctrl+F5). Otherwise the browser can keep an old copy of the listener running and you get duplicate messages. Having two copies of the template deployed does the same.

How it was made

This was built with help from an AI assistant (Claude) and tested on the author's own dashboard.

[{"id":"d1c2b3a495e6f701","type":"tab","label":"Dashboard OnClick","disabled":false,"info":"Dashboard OnClick: click events for Node-RED Dashboard 2.0 widgets. See the comment node for instructions."},{"id":"d1c2b3a495e6f702","type":"comment","z":"d1c2b3a495e6f701","name":"Dashboard OnClick: read me","info":"# Dashboard OnClick\n\nDashboard OnClick: click events for Dashboard 2.0 widgets\n\nA community template node for Node-RED Dashboard 2.0 (not an official FlowFuse add-on) that makes widgets report clicks. The Dashboard 2.0 widgets have no click event of their own, so this adds one. It works with most of the widgets. See Tested below.\n\n### What it does\n\n- It lets you configure a widget to be clickable by editing the `Class` field of a Dashboard 2.0 widget. Add a class that starts with `gid-`, for example `gid-fridge`.\n- When a widget with such a class is clicked, a message goes out of the template node:\n  - `msg.payload` is the id (`fridge`)\n  - `msg.topic` is the widget type plus `_click` (`gauge_click`, `text_click`, `chart_click` and so on)\n  - `msg.nodeId` is the Node-RED node id of the widget\n- Clickable widgets get a hand cursor and a brief flash when clicked. The flash can be switched off.\n- Widgets without a `gid-` class do nothing and keep their normal cursor.\n- It is a single `ui-template` with its Type set to **Widget (UI-Scoped)**, so one copy covers every page of the dashboard and takes no room in the layout.\n\n### How to use it\n\n1. Import the flow, open the **Dashboard OnClick** template node and select your dashboard in the UI field.\n2. Put `gid-` followed by a name in the Class field of each widget you want to click, for example `gid-fridge`.\n3. Deploy, then reload the dashboard page with Ctrl+F5.\n4. Click a widget and watch the debug sidebar.\n\n### Dashboard 2.0 version 1.33.0 tested widgets\n\n- ui-button\n- ui-button-group\n- ui-chart\n- ui-dropdown\n- ui-file-input\n- ui-form\n- ui-gauge\n- ui-markdown\n- ui-number-input\n- ui-progress\n- ui-slider\n- ui-switch\n- ui-table\n- ui-template\n- ui-text\n- ui-text-field\n- ui-text-input\n\n### Limitations\n\n- It relies on Dashboard 2.0's own CSS class names (`nrdb-ui-widget` and the type class next to it). A future Dashboard update could change those and break it.\n- After editing the template, reload the dashboard page (Ctrl+F5). Otherwise the browser can keep an old copy of the listener running and you get duplicate messages. Having two copies of the template deployed does the same.\n\n### How it was made\n\nThis was built with help from an AI assistant (Claude) and tested on the author's own dashboard.","x":190,"y":60,"wires":[]},{"id":"d1c2b3a495e6f703","type":"ui-template","z":"d1c2b3a495e6f701","group":"","page":"","ui":"","name":"Dashboard OnClick","order":0,"width":0,"height":0,"head":"","format":"<template>\n  <div style='display:none'></div>\n</template>\n\n<script>\n// Dashboard OnClick for Node-RED Dashboard 2.0 (a community template)\n//\n// Makes widgets clickable. Put a class that starts with gid- in a widget's Class field\n// (for example gid-fridge). When that widget is clicked, this node sends a message:\n//   msg.payload = the id (fridge)\n//   msg.topic   = the widget type plus _click (gauge_click, text_click, chart_click, table_click)\n//   msg.nodeId  = the node id of the widget\n// Widgets without a gid- class do nothing. One copy covers the whole dashboard.\nexport default {\n  mounted() {\n    // ---- Settings ----\n    const PREFIX = 'gid-'   // class names starting with this make a widget clickable\n    const FLASH = true      // brief dip when a widget is clicked\n    // ------------------\n\n    // Remove a listener and style left behind by an earlier copy of this template\n    if (window.nrDashboardOnClick) {\n      document.removeEventListener('click', window.nrDashboardOnClick)\n    }\n    const oldStyle = document.getElementById('nr-dashboard-onclick-style')\n    if (oldStyle) oldStyle.remove()\n\n    // Hand cursor on widgets that have an id class, including their labels\n    const style = document.createElement('style')\n    style.id = 'nr-dashboard-onclick-style'\n    style.textContent = `.nrdb-ui-widget[class^='${PREFIX}'], .nrdb-ui-widget[class*=' ${PREFIX}'], .nrdb-ui-widget[class^='${PREFIX}'] label, .nrdb-ui-widget[class*=' ${PREFIX}'] label { cursor: pointer; }`\n    document.head.appendChild(style)\n    this.styleEl = style\n\n    // Find the id class on the widget, or on the elements above it up to its group\n    const findId = (el) => {\n      for (let n = el; n && n !== document.body && !n.classList.contains('nrdb-ui-group'); n = n.parentElement) {\n        for (const c of n.classList) {\n          if (c.startsWith(PREFIX)) return c.slice(PREFIX.length)\n        }\n      }\n      return null\n    }\n\n    // Widget type from its nrdb-ui-xxx class (gauge, text, chart, table and so on)\n    const typeOf = (el) => {\n      for (const c of el.classList) {\n        if (c.startsWith('nrdb-ui-') && c !== 'nrdb-ui-widget') return c.slice(8)\n      }\n      return 'widget'\n    }\n\n    this.clickHandler = (e) => {\n      const widget = e.target.closest('.nrdb-ui-widget')\n      if (!widget) return\n\n      // No id class: not clickable\n      const id = findId(widget)\n      if (!id) return\n\n      const type = typeOf(widget)\n\n      // The same click event reaches every copy of this listener, so only the first one acts\n      if (e.nrClickHandled) return\n      e.nrClickHandled = true\n\n      if (FLASH) {\n        widget.animate(\n          [{ opacity: 1 }, { opacity: 0.45, offset: 0.35 }, { opacity: 1 }],\n          { duration: 300, easing: 'ease-out' }\n        )\n      }\n\n      this.send({\n        topic: type + '_click',\n        payload: id,\n        nodeId: widget.id ? widget.id.replace('nrdb-ui-widget-', '') : ''\n      })\n    }\n\n    window.nrDashboardOnClick = this.clickHandler\n    document.addEventListener('click', this.clickHandler)\n  },\n  beforeUnmount() {\n    document.removeEventListener('click', this.clickHandler)\n    if (this.styleEl) this.styleEl.remove()\n  }\n}\n</script>","storeOutMessages":false,"passthru":false,"resendOnRefresh":true,"templateScope":"widget:ui","className":"","x":170,"y":120,"wires":[["d1c2b3a495e6f704"]]},{"id":"d1c2b3a495e6f704","type":"debug","z":"d1c2b3a495e6f701","name":"clicks","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":350,"y":120,"wires":[]}]

Flow Info

Created 1 day ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • comment (x1)
  • debug (x1)
Other

Tags

  • node-red-dashboard-2 dashboard ui-template click onclick widget
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option