Forum Discussion

mdmason's avatar
mdmason
Regular Visitor
4 years ago

Table like slicer

hi all,

 

I'm trying to create a custom slicer that looks like a table. I have gotten so far as to be able to render the table just fine however when I try and add any kind of interactivity I don't seem to be able to select any of the values:

This doesn't work:

visual.ts

 

export class Visual implements IVisual {
  private target: HTMLElement;
  private host: IVisualHost;
  private selectionManager: ISelectionManager;
  private selectionIdBuilder: ISelectionIdBuilder;

  private table: HTMLParagraphElement;

  constructor(options: VisualConstructorOptions) {
    // constructor body
    this.target = options.element;
    this.host = options.host;
    this.table = document.createElement("table");
    this.target.appendChild(this.table);
    this.selectionManager = this.host.createSelectionManager();
    // ...
  }

  public update(options: VisualUpdateOptions) {
    const dataView: DataView = options.dataViews[0];
    const tableDataView: DataViewTable = dataView.table;

    if (!tableDataView) {
      return;
    }
    while (this.table.firstChild) {
      this.table.removeChild(this.table.firstChild);
    }

    //draw header
    const tableHeader = document.createElement("th");
    tableDataView.columns.forEach((column: DataViewMetadataColumn) => {
      const tableHeaderColumn = document.createElement("td");
      tableHeaderColumn.innerText = column.displayName;
      tableHeader.appendChild(tableHeaderColumn);
    });
    this.table.appendChild(tableHeader);

    //draw rows
    tableDataView.rows.forEach((row: DataViewTableRow, rowIndex: number) => {
      const tableRow = document.createElement("tr");
      row.forEach((columnValue: PrimitiveValue) => {
        const cell = document.createElement("td");
        cell.innerText = columnValue.toString();
        tableRow.appendChild(cell);
      });
      this.table.appendChild(tableRow);
      const selection: ISelectionId = this.host
        .createSelectionIdBuilder()
        .withTable(dataView.table, rowIndex)
        .createSelectionId();
    });
  }
}

 

 

 capabilities.json

 

{
  "dataRoles": [
    {
      "name": "values",
      "kind": "GroupingOrMeasure",
      "displayName": "Values"
    }
  ],
  "dataViewMappings": [
    {
      "table": {
        "rows": {
          "select": [
            {
              "for": {
                "in": "values"
              }
            }
          ]
        }
      }
    }
  ]
}

 

really hope someone can troubleshoot my code as I feel like i'm banging my head against a brick wall.

 

EDIT: I feel like I should be adding some kind of onclick logic in here somewhere but god knows where.

 

Thanks

1 Reply

  • mdmason's avatar
    mdmason
    Regular Visitor

    Update, with the following code I am managing to get some output in the console and I can see the other tables on the report refreshing but no filtering is taking place:

     

    export class Visual implements IVisual {
      private settings: VisualSettings;
      private host: IVisualHost;
      private selectionManager: ISelectionManager;
      private selectionIdBuilder: ISelectionIdBuilder;
      private container: d3.Selection<any, any, any, any>;
    
      constructor(options: VisualConstructorOptions) {
        console.log("Visual constructor", options);
        this.host = options.host;
        this.selectionManager = this.host.createSelectionManager();
        /** Visual container */
        this.container = d3select
          .select(options.element)
          .append("div")
          .append("table");
      }
    
      public update(options: VisualUpdateOptions) {
        this.settings = Visual.parseSettings(
          options && options.dataViews && options.dataViews[0]
        );
    
        /** Clear down existing plot */
        this.container.selectAll("*").remove();
    
        /** Test 1: Data view has valid bare-minimum entries */
        let dataViews = options.dataViews;
        console.log("Test 1: Valid data view...");
        if (
          !dataViews ||
          !dataViews[0] ||
          !dataViews[0].table ||
          !dataViews[0].table.rows ||
          !dataViews[0].table.columns ||
          !dataViews[0].metadata
        ) {
          console.log("Test 1 FAILED. No data to draw table.");
          return;
        }
    
        /** If we get this far, we can trust that we can work with the data! */
        let table = dataViews[0].table;
    
        /** Add table heading row and columns */
        let tHead = this.container.append("tr");
        table.columns.forEach((col) => {
          tHead.append("th").text(col.displayName);
        });
    
        /** Now add rows and columns for each row of data */
        table.rows.forEach((row, rowIndex) => {
          let tRow = this.container.append("tr");
          const selection: ISelectionId = this.host
            .createSelectionIdBuilder()
            .withTable(table, rowIndex)
            .createSelectionId();
    
          tRow.on("click", (d) => {
            if (this.host.hostCapabilities.allowInteractions) {
              this.selectionManager.select(selection);
              console.log(selection);
            }
          });
    
          row.forEach((col) => {
            tRow.append("td").text(col.toString());
          });
        });
        console.log("Table rendered!");
      }
    
      private static parseSettings(dataView: DataView): VisualSettings {
        return VisualSettings.parse(dataView) as VisualSettings;
      }
    
    
      public enumerateObjectInstances(
        options: EnumerateVisualObjectInstancesOptions
      😞 VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
        return VisualSettings.enumerateObjectInstances(
          this.settings || VisualSettings.getDefault(),
          options
        );
      }
    }