Re-run query on dashboard variable updated

Hi there,

I’m trying to develop my own Datasource plugin (frontend only) that fetches data from my API and I’m trying to add variable support to it following the guide.

I was able to implement this with a Select Input that chooses a variable, and the getValuesForVariable function from the guide (which in turn uses getTemplateSrv().replace) to get the values for that variable name when running the query. However I ran into an issue where the datasource query is only triggered when the dashboard loads or the refresh button is used. If I change the value of any variable (despite being in use or not) the queries are not re-run and the panels stay the same. If I change the variable value and manually refresh the dashboard the panels are updates as intended.

I’ve looked into a few community posts but none solved the issue:

  • Issue 1 - I tested using a normal text Input field but the same thing happened
  • Issue 2 - I tried to use the event bus to listen for updates on the variable value but no events are triggered. If I subscribe to query-start, or other events, it works but not with variable related ones.

Please let me know if I’m missing something from the documentation or some other issue. Thanks for the help!

However I ran into an issue where the datasource query is only triggered when the dashboard loads or the refresh button is used.

This is the intended way Grafana works. Datasources don’t decide when to send data or to update variables. That’s something the user decides.

If you are talking about the query editor, there’s a prop passed to the QueryEditor called onRunQuery that you can call (without passing anything to it) and it’ll trigger the query run.

e.g. of a Query Editor using this

export function QueryEditor({ query, onChange, onRunQuery }: Props) {
  const fixedUrl = 'https://dummyjson.com/';
  const inputValue = query.queryText?.startsWith(fixedUrl) 
    ? query.queryText.slice(fixedUrl.length)
    : query.queryText || '';

  const onQueryTextChange = (event: ChangeEvent<HTMLInputElement>) => {
    onChange({ ...query, queryText: fixedUrl + event.target.value });
    onRunQuery(); //runs on text change
  };

  return (
    <Stack gap={0}>
      <InlineField label="API Endpoint" labelWidth={16} tooltip="Enter the path after https://dummyjson.com/">
        <Input
          id="query-editor-query-text"
          onChange={onQueryTextChange}
          value={inputValue}
          required
          placeholder="Enter endpoint path (e.g. 'products/1')"
          addonBefore={fixedUrl}
        />
      </InlineField>
    </Stack>
  );
}

in your datasource.ts file, you must make sure your query method is using getTemplateSrv().replace(query, options.scopedVars);

example for the previous query editor:

  async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> {
    // Return a constant for each query.
    const data = await Promise.all(options.targets.map(async (target) => {
      const query = target.queryText;
      const finalQuery = getTemplateSrv().replace(query, options.scopedVars); // variable replacing
      console.log("Fetching data from: " + finalQuery);
      const req = await fetch(finalQuery);
      const todos = await req.json();
      return createDataFrame({
        refId: target.refId,
        fields: [
          { name: "id", values: todos.todos.map((todo: any) => todo.id), type: FieldType.number },
          { name: 'Title', values: todos.todos.map((todo: any) => todo.todo), type: FieldType.string },
          { name: "Completed", values: todos.todos.map((todo: any) => todo.completed), type: FieldType.boolean },
        ],
      });
    }));

    return { data };
  }

what is very important to mention is that the query MUST contain a variable that is defined in the dashboard for grafana to prompt the datasource to query.

For example if in your dashboard there’s a variable called $limit and the user writes a query like

"SELECT* FROM TABLE WHERE id = 1 LIMIT $limit"

Grafana will now know whenever the variable $limit changes it should re-trigger this datasource. It will not trigger datasources that have queries without variables in the dashboard.

Bottom line:

  • make sure you are using getTemplateSrv().replace to interpolate variables in your datasource
  • make sure the query the user is writing in your query editor is using variables
  • if you are 100% sure about the previous point, make sure you are using the correct variable name (the name in the variable editor, not the label)
  • just to be sure, variables in queries look like this: $variable (like in Perl or PHP :wink: )

I tested all this locally with a fresh bootstrapped plugin with create-plugin and it is all working as expected

Hi @academo.
Thank you for the detailed explanation! I was able to figure out the issue.

It was related with using a Select Input instead of a Text input to choose a variable. In my previous solution, the values on the Select Input were equal to the names of the variables, and when running the getTemplateSrv().replace I would prepend the Select output with a '$'. The fix was just changing the Select Input values to be equal to "${variable}" and doing getTemplateSrv().replace directly on the Select output.

Thank you again for the help!