Microsoft is giving away 50,000 FREE Microsoft Certification exam vouchers!
Enter the sweepstakes now!Preparing for a certification exam? Ask exam experts all your questions on May 15th. 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;}
}
Check out the April 2025 Power BI update to learn about new features.
Explore and share Fabric Notebooks to boost Power BI insights in the new community notebooks gallery.
User | Count |
---|---|
14 | |
5 | |
3 | |
3 | |
2 |
User | Count |
---|---|
16 | |
13 | |
7 | |
5 | |
4 |