Don't miss your chance to take the Fabric Data Engineer (DP-600) exam for FREE! Find out how by attending the DP-600 session on April 23rd (pacific time), live or on-demand.
Learn moreNext up in the FabCon + SQLCon recap series: The roadmap for Microsoft SQL and Maximizing Developer experiences in Fabric. All sessions are available on-demand after the live show. Register now
Hello Power BI Community,
I am experiencing an issue with a custom Power BI visual that I am developing. The visual works perfectly during development when using pbiviz start, but after packaging it using pbiviz package, the filtering functionality does not work at all, no values are modified in the report where I m using it because of the filtering.
There are no errors or missing steps shown in the console related to the filtering. In picture you have my applydatefilter function that I use for the filtering in my custom visual if you want to check.
Has anyone encountered a similar issue with Power BI custom visuals? What could be the possible reasons for this discrepancy between development and packaged visual behavior?
Thank you in advance for your assistance!
Hi @TheMoM,
What type of filter effects not works? The default visual filter or the custom filter effects? Can you please share some more detail about these?
How to Get Your Question Answered Quickly
Regards,
Xiaoxin Sheng
The visual of the filter work well, what does not work is the filter when I m using pbiviz package which means when modifying the dates, the other data in the report does not change, but somehow this problem is not present when using pbiviz start to show the visual. I m also thinking right now that the problem is not in the filter function, so I will give you my entire visual.ts code if you want to check. Also, the console.log will not help me to find the error because when using it every function seem to work fine.
Here’s my visual.ts code :
"use strict";
// Import necessary libraries and styles
import "core-js/stable";
import "regenerator-runtime/runtime";
import './../style/visual.less';
import 'bootstrap-slider/dist/css/bootstrap-slider.min.css';
import Slider from 'bootstrap-slider';
import * as $ from 'jquery';
import powerbi from "powerbi-visuals-api";
// Import Power BI types
import DataView = powerbi.DataView;
import IVisualHost = powerbi.extensibility.IVisualHost;
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import { AdvancedFilter, IFilterColumnTarget } from "powerbi-models";
// Import settings model
import { VisualFormattingSettingsModel } from "./settings";
// Interface for date range data points
interface DateRangeDataPoint {
category: string;
minDate: string;
maxDate: string;
}
// Main Visual class
export class Visual implements powerbi.extensibility.visual.IVisual {
private target: HTMLElement;
private host: IVisualHost;
private dateRangeContainer: HTMLDivElement;
private dateInputStart: HTMLInputElement;
private dateInputEnd: HTMLInputElement;
private sliderElement: HTMLInputElement;
private sliderInstance: Slider;
private settings: VisualFormattingSettingsModel;
private minDateValue: number;
private maxDateValue: number;
private isApplyingFilter: boolean = false;
private lastAppliedStartDate: string;
private lastAppliedEndDate: string;
// Constructor
constructor(options: VisualConstructorOptions) {
this.target = options.element;
this.host = options.host;
// Create date range container and inputs
this.dateRangeContainer = document.createElement('div');
this.dateRangeContainer.className = 'date-range-container';
this.dateInputStart = document.createElement('input');
this.dateInputStart.type = 'date';
this.dateInputStart.className = 'date-input';
this.dateInputEnd = document.createElement('input');
this.dateInputEnd.type = 'date';
this.dateInputEnd.className = 'date-input';
this.sliderElement = document.createElement('input');
this.sliderElement.type = 'text';
this.sliderElement.className = 'slider';
this.dateRangeContainer.appendChild(this.dateInputStart);
this.dateRangeContainer.appendChild(this.dateInputEnd);
this.target.appendChild(this.dateRangeContainer);
this.target.appendChild(this.sliderElement);
this.initializeSlider();
// Add event listeners to date inputs
this.dateInputStart.addEventListener('change', () => this.onDateInputChange());
this.dateInputEnd.addEventListener('change', () => this.onDateInputChange());
}
// Initialize the slider
private initializeSlider() {
this.sliderInstance = new Slider(this.sliderElement, {
min: 0,
max: 100,
value: [0, 100],
tooltip: 'hide',
tooltip_split: false
});
// Add event listener for slider stop event
this.sliderInstance.on('slideStop', (event) => {
const values = this.sliderInstance.getValue();
const minDate = values[0];
const maxDate = values[1];
this.dateInputStart.value = new Date(minDate).toISOString().split('T')[0];
this.dateInputEnd.value = new Date(maxDate).toISOString().split('T')[0];
this.applyDateFilter(this.dateInputStart.value, this.dateInputEnd.value);
});
}
// Update slider range
private updateSliderRange(minDateValue: number, maxDateValue: number) {
if (this.minDateValue !== minDateValue || this.maxDateValue !== maxDateValue) {
this.sliderInstance.setAttribute('min', minDateValue);
this.sliderInstance.setAttribute('max', maxDateValue);
this.sliderInstance.setValue([minDateValue, maxDateValue]);
this.dateInputStart.value = new Date(minDateValue).toISOString().split('T')[0];
this.dateInputEnd.value = new Date(maxDateValue).toISOString().split('T')[0];
// Save the new values to prevent unnecessary updates
this.minDateValue = minDateValue;
this.maxDateValue = maxDateValue;
}
}
// Update function called by Power BI
public async update(options: VisualUpdateOptions) {
if (this.isApplyingFilter) {
return;
}
if (options.dataViews && options.dataViews[0]) {
const dataView: DataView = options.dataViews[0];
const dateRangeDataPoints = this.createSelectorDataPoints(options, this.host);
if (dateRangeDataPoints.length > 0) {
const newMinDateValue = new Date(dateRangeDataPoints[0].minDate).getTime();
const newMaxDateValue = new Date(dateRangeDataPoints[0].maxDate).getTime();
if (newMinDateValue !== this.minDateValue || newMaxDateValue !== this.maxDateValue) {
this.updateSliderRange(newMinDateValue, newMaxDateValue);
this.applyDateFilter(this.dateInputStart.value, this.dateInputEnd.value);
// Sleep for 10 seconds to prevent re-entrant calls
await new Promise((resolve) => setTimeout(resolve, 10000));
}
} else {
this.clear();
}
} else {
this.clear();
}
}
// Create selector data points from data view
private createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): DateRangeDataPoint[] {
const dateRangeDataPoints: DateRangeDataPoint[] = [];
const dataViews = options.dataViews;
if (!dataViews || !dataViews[0]) {
return dateRangeDataPoints;
}
const dataView = dataViews[0];
if (!dataView.categorical) {
return dateRangeDataPoints;
}
const categorical = dataView.categorical;
if (!categorical.categories || !categorical.values) {
return dateRangeDataPoints;
}
const category = categorical.categories[0];
const minDateValue = categorical.values[0];
const maxDateValue = categorical.values[1];
if (!category || !minDateValue || !maxDateValue) {
return dateRangeDataPoints;
}
// Assuming you only need the first value
dateRangeDataPoints.push({
category: `${category.values[0]}`,
minDate: this.ensureDateFormat(`${minDateValue.values[0]}`),
maxDate: this.ensureDateFormat(`${maxDateValue.values[0]}`)
});
return dateRangeDataPoints;
}
// Ensure date format is correct
private ensureDateFormat(dateString: string): string {
const date = new Date(dateString);
return date.toISOString().split('.')[0] + "Z";
}
// Clear the visual
private clear() {
this.sliderInstance.setValue([0, 100]);
this.dateInputStart.value = "";
this.dateInputEnd.value = "";
}
// Event handler for date input change
private onDateInputChange() {
const startDate = new Date(this.dateInputStart.value).getTime();
const endDate = new Date(this.dateInputEnd.value).getTime();
this.sliderInstance.setValue([startDate, endDate]);
this.applyDateFilter(this.dateInputStart.value, this.dateInputEnd.value);
}
// Apply date filter
private async applyDateFilter(startDate: string, endDate: string): Promise<void> {
if (this.lastAppliedStartDate === startDate && this.lastAppliedEndDate === endDate) {
return;
}
this.lastAppliedStartDate = startDate;
this.lastAppliedEndDate = endDate;
const target: IFilterColumnTarget = {
table: "document",
column: "document_creation_date"
};
const filter = new AdvancedFilter(target, "And", [
{
operator: "GreaterThanOrEqual",
value: this.ensureDateFormat(startDate)
},
{
operator: "LessThanOrEqual",
value: this.ensureDateFormat(endDate)
}
]);
this.isApplyingFilter = true;
(this.host as any).applyJsonFilter(
filter,
"dataPoint",
"filter",
powerbi.FilterAction.merge
);
this.isApplyingFilter = false;}
}
If you have recently started exploring Fabric, we'd love to hear how it's going. Your feedback can help with product improvements.
A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.
Share feedback directly with Fabric product managers, participate in targeted research studies and influence the Fabric roadmap.
| User | Count |
|---|---|
| 1 | |
| 1 | |
| 1 | |
| 1 | |
| 1 |
| User | Count |
|---|---|
| 4 | |
| 3 | |
| 3 | |
| 3 | |
| 2 |