How to listen for when a variable changes?

Hello,

How Can I listen on grafana variables change from my custom plugin code that is implemented in react ? I need to update my custom panel according to a variable changes.

I didn’t find any documentation regarding this topic.

I am using Grafana 8.1 on Windows 10.

Thanks in advance.

1 Like

Hello,

Same question here. I have a frontend panel plugin which updates the variables, and I have a backend data source plugin(which also has a frontend React part) in which I want to listen to those variables and send them to the backend.

I tried with getTemplateSrv and then getVariables but for some reason its returning me some random variables I had a few days ago, not the current ones which is very odd.

Have you managed to solve this? I’m browsing the community and came upon this post which is identical to my situation. Thanks in advance!

Panels that interpolate template variables should update whenever the value changes.

How to interpolate a template variable depends on whether it’s a panel or a data source.

@igorkujacic12 I’m not sure why you’re getting old values though. How are you retrieving the interpolated values?

Thanks for answering! My pc probably got messed up from spamming changes, when I reinstalled Grafana and made new variables the problem with old variables went away.

I have a custom panel that I wish to update the variables with(that part works fine). The other plugin is a custom backend data source made with springboot/react, and I would like to get those values from the variables on the backend as Strings so I was trying with Text box variables.

Since I’m a backend guy, I noticed that what I’m doing isn’t right. I put the code for getting the variables in the QueryEditor.tsx since from there I was already sending some input values to backend with queries(in the Json part of the Query). I used getTemplateSrv().getVariables(). And that works fine, whenever I go in Edit view of the data source, where I trigger the QueryEditor, it gets sent back.

The problem is when I’m in the dashboard, it doesn’t pick up variable changes and that makes sense, since its in QueryEditor :smiley: If I update the variable from the dashboard, the query in the data source runs again, but it doesn’t pick up the updated values.
Do you have any advice on this, am I using the wrong type of variable(am I supposed to use query variables)? Or am I simply doing it wrong

TemplateSrv only helps you with reading and accessing the variables. If you want to update a template variable, you need to use getLocationSrv().

For more information, check out Set a variable from your plugin.

Hello,

I also observed that my panel does not refresh when a variable changes.
I followed the link mentioned earlier: click and tried the following:

export const myCustomPanel = (props) => {
    const { data, options, timeRange, width, replaceVariables } = props;
    const query = replaceVariables('hello $Language');
  
    return <pre>{ JSON.stringify(query)}</pre>;
}

But then the variable changes, the panel is not updated unless I do a manual refresh - I always see the initial value.
Any ideas what I might be missing? I’m new to grafana, any help is appreciated :slight_smile:

1 Like

Hi Simones,

I’m just letting you know I had this issue for the past few days and I noticed that this issue rose only when I upgraded from Grafana 8.1.5 to 8.3.4 (and later versions too).

In 8.1.5 the panel would automatically refresh and receive the latest variable whenever the user changes the dashboard however in the newer version it does not do that. I am not sure if this was intentional or not, maybe intentional to reduce unnecessary refresh/re-renders.

To make it work, I use replaceVariables() inside onChange() functions so it always receives the latest variable changes rather than in the render function as that only loads once and has the old selected variable and also because in the newer versions the variable change does not re-render the panels.

2 Likes

Hi, could you please see my other response to simones, it might be a bug in newer Grafana versions, it used to automatically update the panels with the latest variable whenever the user changes them but now it doesn’t and it only picks up when I put replaceVariables() within onChange() functions.

Thanks for raising this, I’ve let the team know, and they’re looking into it. I’ll update once I know more.

3 Likes

Hi!

I was looking into this, and unfortunately I couldn’t reproduce the issue (was testing with 8.3.4 ).

Here is what I did:

  1. created a custom variable for the dashboard
  2. used the variable in the title of the panel and also in the component by using replaceVariables()
  3. checked if the panel is re-rendering when the variable changes

Based on my tests the Panel component always re-renders when a template variable changes, however to retrieve the value of a template variable the replaceVariable() function needs to be used. Here is the piece of example code that I tested it with:

export function SimplePanel({
  options,
  data,
  width,
  height,
  timeZone,
  timeRange,
  onChangeTimeRange,
  replaceVariables,
}: Props) {
  console.log('Panel rendered. ✔️');

  return (
    <>
      <div>
        <strong>Variable: </strong>
        {replaceVariables('"$myVariable"')}
      </div>
      <TimeSeries
        width={width}
        height={height}
        timeRange={timeRange}
        timeZone={timeZone}
        frames={data.series}
        legend={options.legend}
      >
        {(config, alignedDataFrame) => {
          return (
            <>
              <TooltipPlugin
                config={config}
                data={alignedDataFrame}
                mode={TooltipDisplayMode.Multi}
                timeZone={timeZone}
              />
              <ZoomPlugin config={config} onZoom={onChangeTimeRange} />
            </>
          );
        }}
      </TimeSeries>
    </>
  );
}

Did I misunderstood something @cisco5gaas?
If yes, do you by any chance have a public repo with the example? Thanks!

2 Likes

Hi!

Thanks for your quick investigation.

I followed your example and it seems that the variable update only works if the variable is in the panel title.
As soon as I remove it from the panel title, it does not refresh automatically anymore.

1 Like

Hi,

Thank you for looking into this, can you please look at @simones latest response from 2 days ago? This is what I also confirmed, if you put the variable in the Panel Title like the one in your example, then it fixes the issue and the variables do get updated inside the panel however, if you remove the variable from the Panel title then it does not update anymore.

Please try that and let us know if you’ve found the issue.

@marcusolsson tagging you in case you may be interested.

Hi there, I am getting the same thing as @simones

I wasn’t able to get this to work, but if I plug the variable into the panel title (i.e. name it ${my_var_name} in the Grafana plugin settings), then the variable re-renders on changes in the react side as well. But if I don’t set the title to do this, then changes don’t rerender on the react side.

Here’s a panel plugin for 8.4.2 to showcase this.

import React from 'react';
import { PanelProps } from '@grafana/data';
import { SimpleOptions } from 'types';
import { css, cx } from 'emotion';


interface Props extends PanelProps<SimpleOptions> { }

export const SimplePanel: React.FC<Props> = ({ options, data, width, height, replaceVariables }) => {

  return (
    <div
      className={cx(
        css`
          position: relative;
          width: ${width}px;
          height: ${height}px;
        `
      )}
    >
      {replaceVariables('$var_currency_pair')}
    </div>
  );
};

I’ve taken another look and realized that the title is being passed as a prop. So I guess if the title is dynamic and getting changed when a variable changes, it will cause the component to re-render. But if title isn’t changed, the component won’t re-render, so it won’t grab the latest variable even if it’s changed.

Maybe this isn’t the place, but could there be a way to just pass a variable as a prop to a PanelPlugin rather than having to use this replaceVariables function? The problem is that it doesn’t look like the function isn’t notifying my component of changes so I have to do something hacky (like name my title my variable) in order to get things to work.

You can use useEffect to watch the variable for changes, assign it to a state with useState, then use the state in your render.

import React, {
    useEffect, 
    useState
} from 'react';

const [dashboardVariableICareAbout, setDashboardVariableICareAbout] = useState("");

useEffect(() => {    
   setDashboardVariableICareAbout(replaceVariables('$dashboardVariableICareAbout'));
  },[replaceVariables('$dashboardVariableICareAbout')]);

return (
    <div>
      {dashboardVariableICareAbout}
    </div>
  );
1 Like

This is great! I didn’t realize that you could use the useEffect hook to watch variables not set by useState.

This worked for me

I thought this was fixed after trying the solution by @ollieboyd, but after using it, I realized that I set my panel’s description to use the variable. After I removed my variable in the description, I couldn’t get the useEffect hook to fire. So the problem persists.

Another problem with use the replaceVariables with a useEffect hook is that it’s watching a non-static error, which which cause react to complain when you are running lint and building the panel.

You can use a different linter configuration. For example: Eslint Vscode: Setting up ESLINT in your JavaScript Project with VS Code - DEV Community . I don’t have linter issues with my above code block.

This is my .eslintrc.json

{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": "plugin:react/recommended",
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "react",
        "@typescript-eslint"
    ],
    "rules": {
    }
}

How is your your panel variable being changed?

Thanks Ollieboyd,

I have a “description” value inside of the grafana panel itself set to the variable value. If keep this value set to a grafana variable, it works.

If I remove this variable from the description, then my plugin doesn’t re-render if the variable updates.

To be clear, your trick does work because I can update state whenever the grafana variable changes, which is pretty helpful. The only problem is that I have to set this value inside of a Grafana dashboard instead of in code, which is kinda hacky.