Forum Discussion
Silko
Helper II
10 years agoCustom visual text input (search)
Hi, I have created a custom visual with a text input, which I wanted to use for a search through slicer. For the start I made just a search through table. It worked perfectly fine on development ...
- 10 years ago
If someone didn't see, Microsoft already made custom visual with search capability. It is called Attribute Slicer. You can find it here:
https://app.powerbi.com/visuals/show/AttributeSlicer1652434005853
Silko
Helper II
10 years agoHi, thanks for your replay. I tried web service as well but it is the same.
I will share my code here:
module powerbi.visuals {
export interface CategoryViewModel {
value: string;
identity: string;
color: string;
}
export interface ValueViewModel {
values: any[];
}
export interface ViewModel {
header: any;
values: ValueViewModel[];
}
export class MySlicer implements IVisual {
public static capabilities: VisualCapabilities = {
// This is what will appear in the 'Field Wells' in reports
dataRoles: [
{
name: 'Category',
kind: powerbi.VisualDataRoleKind.Grouping,
}
],
// This tells power bi how to map your roles above into the dataview you will receive
dataViewMappings: [{
categorical: {
categories: {
for: { in: 'Category' },
dataReductionAlgorithm: { top: {} }
}
}
}],
// Objects light up the formatting pane
objects: {
general: {
displayName: data.createDisplayNameGetter('Visual_General'),
properties: {
formatString: {
type: { formatting: { formatString: true } },
},
},
},
}
};
public static converter(dataView: DataView, colors: IDataColorPalette): ViewModel {
var viewModel: ViewModel = {
header: 'Default Header',
values: []
}
if (dataView) {
var data = dataView.categorical.categories;
var metadata = dataView.metadata;
viewModel.header = metadata.columns[0].displayName;
if (data && data.length > 0) {
for (var i = 0, catLength = data[0].values.length; i < catLength; i++) {
viewModel.values.push(data[0].values[i]);
}
}
}
return viewModel;
}
private hostContainer: JQuery;
private table: D3.Selection;
private tHead: D3.Selection;
private tBody: D3.Selection;
private colorPalette: IDataColorPalette;
private searchInput: D3.Selection;
private searchString: string;
/** This is called once when the visual is initialially created */
public init(options: VisualInitOptions): void {
this.colorPalette = options.style.colorPalette.dataColors;
// element is the element in which your visual will be hosted.
this.hostContainer = options.element.css('overflow-x', 'hidden');
this.searchInput = d3.select(options.element.get(0))
.append("input")
.classed("my-input", true)
.attr("type", "text");
this.table = d3.select(options.element.get(0))
.append("table")
.classed('powerbi-sample-table', true);
this.tHead = this.table.append('thead').append('tr').append('th');
this.tBody = this.table.append('tbody');
var slicerVisual = this;
this.searchInput.on("keyup", function () {
var searchString = slicerVisual.searchString = $(this).val().toLowerCase();
slicerVisual.onSearchInput(slicerVisual, searchString);
});
}
public onSearchInput(slicerVisual, searchString) {
var tds = slicerVisual.hostContainer.find("tbody tr");
tds.each(function() {
var rowString = $(this).text().toLowerCase();
if(!searchString || rowString.indexOf(searchString) > -1)
$(this).removeClass("hidden");
else
$(this).addClass("hidden");
})
}
/** Update is called for data updates, resizes & formatting changes */
public update(options: VisualUpdateOptions) {
var dataViews = options.dataViews;
if (!dataViews) return;
this.updateContainerViewports(options.viewport);
var viewModel = MySlicer.converter(dataViews[0], this.colorPalette);
var slicerTitle = this.tHead.text(viewModel.header);
var slicerData = this.tBody;
this.tBody.html("");
for(var row in viewModel.values) {
var rowString = viewModel.values[row] + "";
rowString = rowString.toLowerCase();
if(!this.searchString || rowString.indexOf(this.searchString) > -1)
slicerData.append('tr').append('td').text(viewModel.values[row]);
else
slicerData.append('tr').classed("hidden", true).append('td').text(viewModel.values[row]);
}
}
private updateContainerViewports(viewport: IViewport) {
var width = viewport.width;
var height = viewport.height;
this.tHead.classed('dynamic', width > 400);
this.tBody.classed('dynamic', width > 400);
this.hostContainer.css({
'height': height,
'width': width
});
this.table.attr('width', width);
}
private format(d: number){
var prefix = d3.formatPrefix(d);
return d3.round(prefix.scale(d),2) + ' ' +prefix.symbol
}
}
}Silko
Helper II
10 years agoIf someone didn't see, Microsoft already made custom visual with search capability. It is called Attribute Slicer. You can find it here:
https://app.powerbi.com/visuals/show/AttributeSlicer1652434005853