1+++
2title = "Add support for variables in plugins"
3+++
4
5# Add support for variables in plugins
6
7Variables are placeholders for values, and can be used to create things like templated queries and dashboard or panel links. For more information on variables, refer to [Templates and variables]({{< relref "../../variables/_index.md" >}}).
8
9This guide explains how to leverage template variables in your panel plugins and data source plugins.
10
11We'll see how you can turn a string like this:
12
13```sql
14SELECT * FROM services WHERE id = "$service"
15```
16
17into
18
19```sql
20SELECT * FROM services WHERE id = "auth-api"
21```
22
23Grafana provides a couple of helper functions to interpolate variables in a string template. Let's see how you can use them in your plugin.
24
25## Interpolate variables in panel plugins
26
27For panels, the `replaceVariables` function is available in the PanelProps.
28
29Add `replaceVariables` to the argument list, and pass it a user-defined template string.
30
31```ts
32export const SimplePanel: React.FC<Props> = ({ options, data, width, height, replaceVariables }) => {
33  const query = replaceVariables('Now displaying $service');
34
35  return <div>{query}</div>;
36};
37```
38
39## Interpolate variables in data source plugins
40
41For data sources, you need to use the getTemplateSrv, which returns an instance of TemplateSrv.
42
431. Import `getTemplateSrv` from the `runtime` package.
44
45   ```ts
46   import { getTemplateSrv } from '@grafana/runtime';
47   ```
48
491. In your `query` method, call the `replace` method with a user-defined template string.
50
51   ```ts
52   async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> {
53     const query = getTemplateSrv().replace('SELECT * FROM services WHERE id = "$service"', options.scopedVars);
54
55     const data = makeDbQuery(query);
56
57     return { data };
58   }
59   ```
60
61## Format multi-value variables
62
63When a user selects multiple values for variable, the value of the interpolated variable depends on the [variable format](https://grafana.com/docs/grafana/next/variables/advanced-variable-format-options/).
64
65A data source can define the default format option when no format is specified by adding a third argument to the interpolation function.
66
67Let's change the SQL query to use CSV format by default:
68
69```ts
70getTemplateSrv().replace('SELECT * FROM services WHERE id IN ($service)', options.scopedVars, 'csv');
71```
72
73Now, when users write `$service`, the query looks like this:
74
75```sql
76SELECT * FROM services WHERE id IN (admin,auth,billing)
77```
78
79For more information on the available variable formats, refer to [Advanced variable format options]({{< relref "../../variables/advanced-variable-format-options.md" >}}).
80
81## Set a variable from your plugin
82
83Not only can you read the value of a variable, you can also update the variable from your plugin. Use LocationSrv.update()
84
85The following example shows how to update a variable called `service`.
86
87- `query` contains the query parameters you want to update. Query parameters controlling variables are prefixed with `var-`.
88- `partial: true` makes the update only affect the query parameters listed in `query`, and leaves the other query parameters unchanged.
89- `replace: true` tells Grafana to update the current URL state, rather than creating a new history entry.
90
91```ts
92import { getLocationSrv } from '@grafana/runtime';
93```
94
95```ts
96getLocationSrv().update({
97  query: {
98    'var-service': 'billing',
99  },
100  partial: true,
101  replace: true,
102});
103```
104
105> **Note:** Grafana queries your data source whenever you update a variable. Excessive updates to variables can slow down Grafana and lead to a poor user experience.
106
107## Add support for query variables to your data source
108
109[Query variables]({{< relref "../../variables/variable-types/add-query-variable.md" >}}) is a type of variable that allows you to query a data source for the values. By adding support for query variables to your data source plugin, users can create dynamic dashboards based on data from your data source.
110
111Let's start by defining a query model for the variable query.
112
113```ts
114export interface MyVariableQuery {
115  namespace: string;
116  rawQuery: string;
117}
118```
119
120For a data source to support query variables, you must override the `metricFindQuery` in your `DataSourceApi` class. `metricFindQuery` returns an array of `MetricFindValue` which has a single property, `text`:
121
122```ts
123async metricFindQuery(query: MyVariableQuery, options?: any) {
124  // Retrieve DataQueryResponse based on query.
125  const response = await this.fetchMetricNames(query.namespace, query.rawQuery);
126
127  // Convert query results to a MetricFindValue[]
128  const values = response.data.map(frame => ({ text: frame.name }));
129
130  return values;
131}
132```
133
134> **Note:** By default, Grafana provides a default query model and editor for simple text queries. If that's all you need, then you can leave the query type as `string`.
135>
136> ```ts
137> async metricFindQuery(query: string, options?: any)
138> ```
139
140Let's create a custom query editor to allow the user to edit the query model.
141
1421. Create a `VariableQueryEditor` component.
143
144   ```ts
145   import React, { useState } from 'react';
146   import { MyVariableQuery } from './types';
147
148   interface VariableQueryProps {
149     query: MyVariableQuery;
150     onChange: (query: MyVariableQuery, definition: string) => void;
151   }
152
153   export const VariableQueryEditor: React.FC<VariableQueryProps> = ({ onChange, query }) => {
154     const [state, setState] = useState(query);
155
156     const saveQuery = () => {
157       onChange(state, `${state.query} (${state.namespace})`);
158     };
159
160     const handleChange = (event: React.FormEvent<HTMLInputElement>) =>
161       setState({
162         ...state,
163         [event.currentTarget.name]: event.currentTarget.value,
164       });
165
166     return (
167       <>
168         <div className="gf-form">
169           <span className="gf-form-label width-10">Namespace</span>
170           <input
171             name="namespace"
172             className="gf-form-input"
173             onBlur={saveQuery}
174             onChange={handleChange}
175             value={state.namespace}
176           />
177         </div>
178         <div className="gf-form">
179           <span className="gf-form-label width-10">Query</span>
180           <input
181             name="rawQuery"
182             className="gf-form-input"
183             onBlur={saveQuery}
184             onChange={handleChange}
185             value={state.rawQuery}
186           />
187         </div>
188       </>
189     );
190   };
191   ```
192
193   Grafana saves the query model whenever one of the text fields loses focus (`onBlur`) and then previews the values returned by `metricFindQuery`.
194
195   The second argument to `onChange` allows you to set a text representation of the query which will appear next to the name of the variable in the variables list.
196
1971. Finally, configure your plugin to use the query editor.
198
199   ```ts
200   import { VariableQueryEditor } from './VariableQueryEditor';
201
202   export const plugin = new DataSourcePlugin<DataSource, MyQuery, MyDataSourceOptions>(DataSource)
203     .setQueryEditor(QueryEditor)
204     .setVariableQueryEditor(VariableQueryEditor);
205   ```
206
207That's it! You can now try out the plugin by adding a [query variable]({{< relref "../../variables/variable-types/add-query-variable.md" >}}) to your dashboard.
208