Forum Discussion
dunkyboy
4 years agoFrequent Visitor
Difficulty binding selection to custom table visual
Having followed the following, i'm having great difficulty in getting my table to recognise a row selection.
Power BI visuals interactivity utils - Power BI | Microsoft Docs
Versions:
"powerbi-models": "^1.9.8",
"powerbi-visuals-api": "~3.8.0",
"powerbi-visuals-utils-dataviewutils": "^2.4.1",
"powerbi-visuals-utils-interactivityutils": "^5.7.1"
I think it's related to this code, that I was unable to work out how to implement. MS seems to be lacking simple table templates.
this.interactivity.bind(<BaseBehaviorOptions<VisualDataPoint>>{
behavior: this.behavior,
dataPoints: this.categories,
clearCatcherSelection: select(this.target),
elementsSelection: selectionMerge
});
Here's my code.
"use strict";
declare var require: any
import "./../style/visual.less";
import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import ISelectionManager = powerbi.extensibility.ISelectionManager;
import ISelectionIdBuilder = powerbi.extensibility.ISelectionIdBuilder;
import ISelectionId = powerbi.visuals.ISelectionId;
import EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions;
import VisualObjectInstance = powerbi.VisualObjectInstance;
import DataView = powerbi.DataView;
import DataViewTableRow = powerbi.DataViewTableRow;
import VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject;
import { interactivityBaseService, interactivitySelectionService } from "powerbi-visuals-utils-interactivityutils";
// import VisualDataPoint = interactivityBaseService.BaseDataPoint;
export interface VisualDataPoint extends interactivitySelectionService.SelectableDataPoint {
value: powerbi.PrimitiveValue;
}
import {baseBehavior } from "powerbi-visuals-utils-interactivityutils";
import * as d3select from 'd3-selection';
import * as d3 from 'd3';
import { VisualSettings } from "./settings";
import { SelectableDataPoint } from "powerbi-visuals-utils-interactivityutils/lib/interactivitySelectionService";
import { IBehaviorOptions, BaseDataPoint, IInteractiveBehavior, ISelectionHandler, InteractivityBaseService } from "powerbi-visuals-utils-interactivityutils/lib/interactivityBaseService";
import { csvParse, randomBernoulli } from "d3";
export interface BaseBehaviorOptions<SelectableDataPointType extends BaseDataPoint> extends IBehaviorOptions<SelectableDataPointType> {
/** d3 selection object of the main elements on the chart */
elementsSelection: d3.Selection<any, SelectableDataPoint, any, any>;
/** d3 selection object of some elements on backgroup, to hadle click of reset selection */
clearCatcherSelection: d3.Selection<any, any, any, any>;
}
const getEvent = () => require("d3-selection").event;
export class Visual implements IVisual {
private host: IVisualHost;
private target: HTMLElement;
private selectionManager: ISelectionManager;
private container: d3.Selection<any, any, any, any>;
private settings: VisualSettings;
private interactivity: interactivityBaseService.IInteractivityService<VisualDataPoint>;
private behavior: interactivityBaseService.IInteractiveBehavior;
// private behavior: interactivityBaseService.ISelectionHandler;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.host = options.host;
this.container = d3select.select(options.element)
.append('table');
this.selectionManager = options.host.createSelectionManager();
this.interactivity = interactivitySelectionService.createInteractivitySelectionService(this.host);
this.behavior = new Behavior1();
}
public update(options: VisualUpdateOptions) {
this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]);
console.log('Visual update', options);
this.container.selectAll('*').remove();
let dataViews = options.dataViews;
//
const dataView = dataViews[0];
let table = dataViews[0].table;
let tHead = this.container
.append('tr');
table.columns.forEach(
(col) => {
tHead.append('th').text(col.displayName);
},
);
tHead.append('th').text('Test');
table.rows.forEach(
(row: DataViewTableRow, rowIndex: number) => {
let tRow = this.container
.append('tr');
row.forEach(
(col) => {
tRow.append('td')
.text(col.toString());
},
)
const selectionId: ISelectionId = this.host.createSelectionIdBuilder()
.withTable(dataView.table, rowIndex)
.createSelectionId();
}
);
}
private static parseSettings(dataView: DataView): VisualSettings {
return <VisualSettings>VisualSettings.parse(dataView);
}
/**
* This function gets called for each of the objects defined in the capabilities files and allows you to select which of the
* objects and properties you want to expose to the users in the property pane.
*
*/
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
}
}
export class Behavior1<SelectableDataPointType extends BaseDataPoint> implements IInteractiveBehavior {
/** d3 selection object of main elements in the chart */
protected options: BaseBehaviorOptions<SelectableDataPointType>;
protected selectionHandler: ISelectionHandler;
protected bindClick() {
console.log('Button Click');
const {
elementsSelection
} = this.options;
elementsSelection.on("click", (datum) => {
console.log('Button Click YYYYYY');
const mouseEvent: MouseEvent = (getEvent() as MouseEvent) || window.event as MouseEvent;
mouseEvent && this.selectionHandler.handleSelection(
datum,
mouseEvent.ctrlKey);
});
}
protected bindClearCatcher() {
// ...
}
protected bindContextMenu() {
console.log('Button Click');
const {
elementsSelection
} = this.options;
elementsSelection.on("contextmenu", (datum) => {
const event: MouseEvent = (getEvent() as MouseEvent) || window.event as MouseEvent;
if (event) {
console.log('Button Click');
this.selectionHandler.handleContextMenu(
datum,
{
x: event.clientX,
y: event.clientY
});
event.preventDefault();
}
});
}
public bindEvents(
options: BaseBehaviorOptions<SelectableDataPointType>,
selectionHandler: ISelectionHandler): void {
console.log('Call Bind events');
this.options = options;
this.selectionHandler = selectionHandler;
this.bindClick();
this.bindClearCatcher();
this.bindContextMenu();
}
public renderSelection(hasSelection: boolean): void {
console.log('Call RenderSelection');
this.options.elementsSelection.style("color", (category: any) => {
if (category.selected) {
return 'blue';
} else {
return 'red';
}
});
}
}
1 Reply
- AbdulRKzaiNew Member
hi, its been a while, did you get any info on this. can you please sahre if you have any solution.
thanks