Advance your Data & AI career with 50 days of live learning, dataviz contests, hands-on challenges, study groups & certifications and more!
Get registeredGet Fabric Certified for FREE during Fabric Data Days. Don't miss your chance! Request now
Does anyone know how to use two measures in a custom visual? I've seen a thread called "Adding a Second Measure to Custom Visual" where they use two measures by categorising them and then using a chart, I'm trying to do a way more simple thing which is just using two measures in a plain card and the problem I'm seeing is that I don't quite understand how to do it without categorising it. When done with only one measure the code is pretty simple (it's the circle example), is there any way to mantain that simplicity when done with two?
The code with one measure:
{
Solved! Go to Solution.
Hi @antalgu,
You can't maintain the simplicity of a single dataViewMapping for multiple measures or columns, as it introduces additional context into the generated DAX query that you will need to handle. single can only support one value in the visual query, and therefore you can only have one dataRole with a single measure in these cases.
Approach 1
The most 'straightforward' way to do this is using categorical and just binding the data roles to the values object (ignoring categories). You will then need to map your data from the appropriate data roles in the dataView.
Here's an example capabilities.json for this idea this using two dataRoles with a single measure in each:
{
"dataRoles": [
{
"displayName": "Measure",
"description": "Add your measure here to display its value in the card.",
"name": "measure",
"kind": "Measure"
},
{
"displayName": "Tooltip",
"description": "Additional measures to display in the tooltip.",
"name": "tooltip",
"kind": "Measure"
}
],
"objects": { },
"dataViewMappings": [
{
"categorical": {
"values": {
"select": [
{
"bind": {
"to": "measure"
}
},
{
"bind": {
"to": "tooltip"
}
}
]
}
},
"conditions": [
{
"measure": {
"max": 1
},
"tooltip": {
"max": 1
}
}
]
}
]
}
For the above example, because we know that there will only ever be a maximum of one value per dataRole, one approach to obtain the values from the dataView using known dataRoles would be as follows (in the visual's update function):
const
measureValue = options.dataViews[0].categorical.values[0]?.values[0],
tooltipValue = options.dataViews[0].categorical.values[1]?.values[0];
The ? after each categorical.values array element prevents the visual from crashing if the element doesn't exist (as trying to access it's values property will cause an error).
A more resilient way (particularly if you might have multiple dataRoles and can't be 100% sure what youre users will be adding - is to assign results based on a find against your categorical.values array by specifying the dataRole's name value, e.g.:
const
measureValue = options.dataViews[0].categorical.values
.find(
c => c.source.roles.measure
)?.values[0],
tooltipValue = options.dataViews[0].categorical.values
.find(
c => c.source.roles.tooltip
)?.values[0];
Approach 2
Another possibility is to use table. Here's what the capabilities.json would look like here:
{
"dataRoles": [
{
"displayName": "Measure",
"description": "Add your measure here to display its value in the card.",
"name": "measure",
"kind": "Measure"
},
{
"displayName": "Tooltip",
"description": "Additional measures to display in the tooltip.",
"name": "tooltip",
"kind": "Measure"
}
],
"objects": { },
"dataViewMappings": [
{
"table": {
"rows": {
"select": [
{
"bind": {
"to": "measure"
}
},
{
"bind": {
"to": "tooltip"
}
}
]
}
},
"conditions": [
{
"measure": {
"max": 1
},
"tooltip": {
"max": 1
}
}
]
}
]
}
The simple way of grabbing the values would change to this:
const
measureValue = options.dataViews[0].table.rows[0][0],
tooltipValue = options.dataViews[0].table.rows[0][1];
Again, this relies on all dataRoles being populated. Otherwise, you'll need to mandate a min of 1 in the conditions or write code when investigating the dataView to check that a dataRole is present in the dataView and handle it accordingly.
You should be able to adapt either of these patterns, but if you're still struggling, please post a follow-up with the code you've tried and what you're trying to do (expected output would also be helpful) and we'll see if we can get yout here.
Good luck!
Daniel
Proud to be a Super User!
On how to ask a technical question, if you really want an answer (courtesy of SQLBI)
Hi @antalgu,
You can't maintain the simplicity of a single dataViewMapping for multiple measures or columns, as it introduces additional context into the generated DAX query that you will need to handle. single can only support one value in the visual query, and therefore you can only have one dataRole with a single measure in these cases.
Approach 1
The most 'straightforward' way to do this is using categorical and just binding the data roles to the values object (ignoring categories). You will then need to map your data from the appropriate data roles in the dataView.
Here's an example capabilities.json for this idea this using two dataRoles with a single measure in each:
{
"dataRoles": [
{
"displayName": "Measure",
"description": "Add your measure here to display its value in the card.",
"name": "measure",
"kind": "Measure"
},
{
"displayName": "Tooltip",
"description": "Additional measures to display in the tooltip.",
"name": "tooltip",
"kind": "Measure"
}
],
"objects": { },
"dataViewMappings": [
{
"categorical": {
"values": {
"select": [
{
"bind": {
"to": "measure"
}
},
{
"bind": {
"to": "tooltip"
}
}
]
}
},
"conditions": [
{
"measure": {
"max": 1
},
"tooltip": {
"max": 1
}
}
]
}
]
}
For the above example, because we know that there will only ever be a maximum of one value per dataRole, one approach to obtain the values from the dataView using known dataRoles would be as follows (in the visual's update function):
const
measureValue = options.dataViews[0].categorical.values[0]?.values[0],
tooltipValue = options.dataViews[0].categorical.values[1]?.values[0];
The ? after each categorical.values array element prevents the visual from crashing if the element doesn't exist (as trying to access it's values property will cause an error).
A more resilient way (particularly if you might have multiple dataRoles and can't be 100% sure what youre users will be adding - is to assign results based on a find against your categorical.values array by specifying the dataRole's name value, e.g.:
const
measureValue = options.dataViews[0].categorical.values
.find(
c => c.source.roles.measure
)?.values[0],
tooltipValue = options.dataViews[0].categorical.values
.find(
c => c.source.roles.tooltip
)?.values[0];
Approach 2
Another possibility is to use table. Here's what the capabilities.json would look like here:
{
"dataRoles": [
{
"displayName": "Measure",
"description": "Add your measure here to display its value in the card.",
"name": "measure",
"kind": "Measure"
},
{
"displayName": "Tooltip",
"description": "Additional measures to display in the tooltip.",
"name": "tooltip",
"kind": "Measure"
}
],
"objects": { },
"dataViewMappings": [
{
"table": {
"rows": {
"select": [
{
"bind": {
"to": "measure"
}
},
{
"bind": {
"to": "tooltip"
}
}
]
}
},
"conditions": [
{
"measure": {
"max": 1
},
"tooltip": {
"max": 1
}
}
]
}
]
}
The simple way of grabbing the values would change to this:
const
measureValue = options.dataViews[0].table.rows[0][0],
tooltipValue = options.dataViews[0].table.rows[0][1];
Again, this relies on all dataRoles being populated. Otherwise, you'll need to mandate a min of 1 in the conditions or write code when investigating the dataView to check that a dataRole is present in the dataView and handle it accordingly.
You should be able to adapt either of these patterns, but if you're still struggling, please post a follow-up with the code you've tried and what you're trying to do (expected output would also be helpful) and we'll see if we can get yout here.
Good luck!
Daniel
Proud to be a Super User!
On how to ask a technical question, if you really want an answer (courtesy of SQLBI)
Hi @dm-p,
Thanks for the quick and precise response. Your explanations were great and the code is now working perfectly.
Advance your Data & AI career with 50 days of live learning, contests, hands-on challenges, study groups & certifications and more!
Check out the October 2025 Power BI update to learn about new features.