<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Difficulty binding selection to custom table visual in Custom Visuals Development Discussion</title>
    <link>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Difficulty-binding-selection-to-custom-table-visual/m-p/2551962#M4575</link>
    <description>&lt;P&gt;Having followed the following, i'm having great difficulty in getting my table to recognise a row selection.&lt;/P&gt;&lt;P&gt;&lt;A href="https://docs.microsoft.com/en-us/power-bi/developer/visuals/utils-interactivity-selections" target="_blank" rel="noopener"&gt;Power BI visuals interactivity utils - Power BI | Microsoft Docs&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Versions:&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-models"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"^1.9.8"&lt;/SPAN&gt;&lt;SPAN&gt;,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-visuals-api"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"~3.8.0"&lt;/SPAN&gt;&lt;SPAN&gt;,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-visuals-utils-dataviewutils"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"^2.4.1"&lt;/SPAN&gt;&lt;SPAN&gt;,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-visuals-utils-interactivityutils"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"^5.7.1"&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;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.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;this.interactivity.bind(&amp;lt;BaseBehaviorOptions&amp;lt;VisualDataPoint&amp;gt;&amp;gt;{
    behavior: this.behavior,
    dataPoints: this.categories,
    clearCatcherSelection: select(this.target),
    elementsSelection: selectionMerge
});&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Here's my code.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;"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&amp;lt;SelectableDataPointType extends BaseDataPoint&amp;gt; extends IBehaviorOptions&amp;lt;SelectableDataPointType&amp;gt; {

/** d3 selection object of the main elements on the chart */
elementsSelection: d3.Selection&amp;lt;any, SelectableDataPoint, any, any&amp;gt;;

/** d3 selection object of some elements on backgroup, to hadle click of reset selection */
clearCatcherSelection: d3.Selection&amp;lt;any, any, any, any&amp;gt;;
}

const getEvent = () =&amp;gt; require("d3-selection").event;

export class Visual implements IVisual {
    private host: IVisualHost;
    private target: HTMLElement;
    private selectionManager: ISelectionManager;
    private container: d3.Selection&amp;lt;any, any, any, any&amp;gt;;
    private settings: VisualSettings;
    private interactivity: interactivityBaseService.IInteractivityService&amp;lt;VisualDataPoint&amp;gt;;
    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 &amp;amp;&amp;amp; options.dataViews &amp;amp;&amp;amp; 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) =&amp;gt; {
                tHead.append('th').text(col.displayName);
            },
        );
        
        tHead.append('th').text('Test');

        table.rows.forEach(
            (row: DataViewTableRow, rowIndex: number) =&amp;gt; {
                let tRow = this.container
                    .append('tr');
                    
                row.forEach(

                    (col) =&amp;gt; {
                        tRow.append('td')
                            .text(col.toString());
                    },
                )

                const selectionId: ISelectionId = this.host.createSelectionIdBuilder()
                    .withTable(dataView.table, rowIndex)
                    .createSelectionId();

            }
        );
    }

    private static parseSettings(dataView: DataView): VisualSettings {
        return &amp;lt;VisualSettings&amp;gt;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&amp;lt;SelectableDataPointType extends BaseDataPoint&amp;gt; implements IInteractiveBehavior {

    /** d3 selection object of main elements in the chart */
    protected options: BaseBehaviorOptions&amp;lt;SelectableDataPointType&amp;gt;;
    protected selectionHandler: ISelectionHandler;

    protected bindClick() {
        console.log('Button Click');
        const {
            elementsSelection
        } = this.options;
      
        elementsSelection.on("click", (datum) =&amp;gt; {
            console.log('Button Click YYYYYY');
            const mouseEvent: MouseEvent = (getEvent() as MouseEvent) || window.event as MouseEvent;
            mouseEvent &amp;amp;&amp;amp; this.selectionHandler.handleSelection(
                datum,
                mouseEvent.ctrlKey);
        });
    }

    protected bindClearCatcher() {
      // ...
    }

    protected bindContextMenu() {
        console.log('Button Click');
        const {
            elementsSelection
        } = this.options;
    
        elementsSelection.on("contextmenu", (datum) =&amp;gt; {
            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&amp;lt;SelectableDataPointType&amp;gt;,
        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) =&amp;gt; {
            if (category.selected) {
                return 'blue';
            } else {
                return 'red';
            }
        });
    }
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Thu, 02 Jun 2022 00:55:47 GMT</pubDate>
    <dc:creator>dunkyboy</dc:creator>
    <dc:date>2022-06-02T00:55:47Z</dc:date>
    <item>
      <title>Difficulty binding selection to custom table visual</title>
      <link>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Difficulty-binding-selection-to-custom-table-visual/m-p/2551962#M4575</link>
      <description>&lt;P&gt;Having followed the following, i'm having great difficulty in getting my table to recognise a row selection.&lt;/P&gt;&lt;P&gt;&lt;A href="https://docs.microsoft.com/en-us/power-bi/developer/visuals/utils-interactivity-selections" target="_blank" rel="noopener"&gt;Power BI visuals interactivity utils - Power BI | Microsoft Docs&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Versions:&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-models"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"^1.9.8"&lt;/SPAN&gt;&lt;SPAN&gt;,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-visuals-api"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"~3.8.0"&lt;/SPAN&gt;&lt;SPAN&gt;,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-visuals-utils-dataviewutils"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"^2.4.1"&lt;/SPAN&gt;&lt;SPAN&gt;,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp; &amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;"powerbi-visuals-utils-interactivityutils"&lt;/SPAN&gt;&lt;SPAN&gt;: &lt;/SPAN&gt;&lt;SPAN&gt;"^5.7.1"&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;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.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;this.interactivity.bind(&amp;lt;BaseBehaviorOptions&amp;lt;VisualDataPoint&amp;gt;&amp;gt;{
    behavior: this.behavior,
    dataPoints: this.categories,
    clearCatcherSelection: select(this.target),
    elementsSelection: selectionMerge
});&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Here's my code.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;"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&amp;lt;SelectableDataPointType extends BaseDataPoint&amp;gt; extends IBehaviorOptions&amp;lt;SelectableDataPointType&amp;gt; {

/** d3 selection object of the main elements on the chart */
elementsSelection: d3.Selection&amp;lt;any, SelectableDataPoint, any, any&amp;gt;;

/** d3 selection object of some elements on backgroup, to hadle click of reset selection */
clearCatcherSelection: d3.Selection&amp;lt;any, any, any, any&amp;gt;;
}

const getEvent = () =&amp;gt; require("d3-selection").event;

export class Visual implements IVisual {
    private host: IVisualHost;
    private target: HTMLElement;
    private selectionManager: ISelectionManager;
    private container: d3.Selection&amp;lt;any, any, any, any&amp;gt;;
    private settings: VisualSettings;
    private interactivity: interactivityBaseService.IInteractivityService&amp;lt;VisualDataPoint&amp;gt;;
    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 &amp;amp;&amp;amp; options.dataViews &amp;amp;&amp;amp; 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) =&amp;gt; {
                tHead.append('th').text(col.displayName);
            },
        );
        
        tHead.append('th').text('Test');

        table.rows.forEach(
            (row: DataViewTableRow, rowIndex: number) =&amp;gt; {
                let tRow = this.container
                    .append('tr');
                    
                row.forEach(

                    (col) =&amp;gt; {
                        tRow.append('td')
                            .text(col.toString());
                    },
                )

                const selectionId: ISelectionId = this.host.createSelectionIdBuilder()
                    .withTable(dataView.table, rowIndex)
                    .createSelectionId();

            }
        );
    }

    private static parseSettings(dataView: DataView): VisualSettings {
        return &amp;lt;VisualSettings&amp;gt;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&amp;lt;SelectableDataPointType extends BaseDataPoint&amp;gt; implements IInteractiveBehavior {

    /** d3 selection object of main elements in the chart */
    protected options: BaseBehaviorOptions&amp;lt;SelectableDataPointType&amp;gt;;
    protected selectionHandler: ISelectionHandler;

    protected bindClick() {
        console.log('Button Click');
        const {
            elementsSelection
        } = this.options;
      
        elementsSelection.on("click", (datum) =&amp;gt; {
            console.log('Button Click YYYYYY');
            const mouseEvent: MouseEvent = (getEvent() as MouseEvent) || window.event as MouseEvent;
            mouseEvent &amp;amp;&amp;amp; this.selectionHandler.handleSelection(
                datum,
                mouseEvent.ctrlKey);
        });
    }

    protected bindClearCatcher() {
      // ...
    }

    protected bindContextMenu() {
        console.log('Button Click');
        const {
            elementsSelection
        } = this.options;
    
        elementsSelection.on("contextmenu", (datum) =&amp;gt; {
            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&amp;lt;SelectableDataPointType&amp;gt;,
        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) =&amp;gt; {
            if (category.selected) {
                return 'blue';
            } else {
                return 'red';
            }
        });
    }
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 02 Jun 2022 00:55:47 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Difficulty-binding-selection-to-custom-table-visual/m-p/2551962#M4575</guid>
      <dc:creator>dunkyboy</dc:creator>
      <dc:date>2022-06-02T00:55:47Z</dc:date>
    </item>
    <item>
      <title>Re: Difficulty binding selection to custom table visual</title>
      <link>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Difficulty-binding-selection-to-custom-table-visual/m-p/3459842#M8044</link>
      <description>&lt;P&gt;hi, its been a while, did you get any info on this. can you please sahre if you have any solution.&lt;BR /&gt;&lt;BR /&gt;thanks&lt;/P&gt;</description>
      <pubDate>Wed, 04 Oct 2023 15:43:26 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Custom-Visuals-Development/Difficulty-binding-selection-to-custom-table-visual/m-p/3459842#M8044</guid>
      <dc:creator>AbdulRKzai</dc:creator>
      <dc:date>2023-10-04T15:43:26Z</dc:date>
    </item>
  </channel>
</rss>

