Forum Discussion

dunkyboy's avatar
dunkyboy
Frequent Visitor
4 years ago

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

  • hi, its been a while, did you get any info on this. can you please sahre if you have any solution.

    thanks