Forum Discussion

a-smiggle's avatar
a-smiggle
Regular Visitor
11 months ago

Power BI Custom Visual: Customize series mechanism example

As per this: https://powerbi.microsoft.com/en-us/blog/introducing-the-new-format-pane-preview/

Is there an example on how to get the customize series mechanism.

In my formatting pane I am getting the options succeffully in the dropdown and in the formattingSettings object. But they are not updating.

Return formattingSettings:

{
    "columnWidth": {
        "container": {
            "displayName": "Apply settings to",
            "containerItems": [
                {
                    "width": {
                        "name": "width",
                        "displayName": "Column Width",
                        "description": "Set the width of this column (pixels)",
                        "value": 120,
                        "options": {
                            "maxValue": {
                                "type": 1,
                                "value": 1000
                            },
                            "minValue": {
                                "type": 0,
                                "value": 20
                            }
                        },
                        "type": "NumUpDown"
                    },
                    "name": "row_0",
                    "displayName": "work_year",
                    "slices": [
                        {
                            "name": "width",
                            "displayName": "Column Width",
                            "description": "Set the width of this column (pixels)",
                            "value": 120,
                            "options": {
                                "maxValue": {
                                    "type": 1,
                                    "value": 1000
                                },
                                "minValue": {
                                    "type": 0,
                                    "value": 20
                                }
                            },
                            "type": "NumUpDown"
                        }
                    ]
                },
                {
                    "width": {
                        "name": "width",
                        "displayName": "Column Width",
                        "description": "Set the width of this column (pixels)",
                        "value": 120,
                        "options": {
                            "maxValue": {
                                "type": 1,
                                "value": 1000
                            },
                            "minValue": {
                                "type": 0,
                                "value": 20
                            }
                        },
                        "type": "NumUpDown"
                    },
                    "name": "row_1",
                    "displayName": "job_title",
                    "slices": [
                        {
                            "name": "width",
                            "displayName": "Column Width",
                            "description": "Set the width of this column (pixels)",
                            "value": 120,
                            "options": {
                                "maxValue": {
                                    "type": 1,
                                    "value": 1000
                                },
                                "minValue": {
                                    "type": 0,
                                    "value": 20
                                }
                            },
                            "type": "NumUpDown"
                        }
                    ]
                },
                {
                    "width": {
                        "name": "width",
                        "displayName": "Column Width",
                        "description": "Set the width of this column (pixels)",
                        "value": 120,
                        "options": {
                            "maxValue": {
                                "type": 1,
                                "value": 1000
                            },
                            "minValue": {
                                "type": 0,
                                "value": 20
                            }
                        },
                        "type": "NumUpDown"
                    },
                    "name": "value_0",
                    "displayName": "Sum of salary_in_usd",
                    "slices": [
                        {
                            "name": "width",
                            "displayName": "Column Width",
                            "description": "Set the width of this column (pixels)",
                            "value": 120,
                            "options": {
                                "maxValue": {
                                    "type": 1,
                                    "value": 1000
                                },
                                "minValue": {
                                    "type": 0,
                                    "value": 20
                                }
                            },
                            "type": "NumUpDown"
                        }
                    ]
                },
                {
                    "width": {
                        "name": "width",
                        "displayName": "Column Width",
                        "description": "Set the width of this column (pixels)",
                        "value": 120,
                        "options": {
                            "maxValue": {
                                "type": 1,
                                "value": 1000
                            },
                            "minValue": {
                                "type": 0,
                                "value": 20
                            }
                        },
                        "type": "NumUpDown"
                    },
                    "name": "value_1",
                    "displayName": "RR",
                    "slices": [
                        {
                            "name": "width",
                            "displayName": "Column Width",
                            "description": "Set the width of this column (pixels)",
                            "value": 120,
                            "options": {
                                "maxValue": {
                                    "type": 1,
                                    "value": 1000
                                },
                                "minValue": {
                                    "type": 0,
                                    "value": 20
                                }
                            },
                            "type": "NumUpDown"
                        }
                    ]
                }
            ]
        },
        "name": "columnWidth",
        "displayName": "Column Width"
    }
}



This is what I code have implemented:

- capabilties.json: 

object: {
"columnWidth": {
      "displayName": "Column Widths",
      "properties": {
        "width": {
          "displayName": "Column Width",
          "description": "Set Column Width.",
          "type": {
            "numeric": true
          }
        }
      }
    }
}

- Settings.ts:

import powerbi from "powerbi-visuals-api";
import { formattingSettings } from "powerbi-visuals-utils-formattingmodel";

// Column Width Card for per-column dropdown
export class ColumnWidthCardItem extends formattingSettings.SimpleCard {
    public width: formattingSettings.NumUpDown = new formattingSettings.NumUpDown({
        name: "width",
        displayName: "Column Width",
        description: "Set the width of this column (pixels)",
        value: 120,
        options: {
            maxValue: {
                type: powerbi.visuals.ValidatorType.Max,
                value: 1000
            },
            minValue: {
                type: powerbi.visuals.ValidatorType.Min,
                value: 20
            }
        }
    });
    constructor(name?: string, displayName?: string, widthValue?: number) {
        super();
        this.name = name || "";
        this.displayName = displayName || name || "";
        if (typeof widthValue === "number") {
            this.width.value = widthValue;
        }
        this.slices = [this.width];
    }
}

class ColumnWidthCardSetting extends formattingSettings.SimpleCard {

  
    public container: formattingSettings.Container = {
        displayName: "Apply settings to",
        containerItems:[new ColumnWidthCardItem()]
    };

    constructor() {
        super();
        this.name = "columnWidth";
        this.displayName = "Column Width";
    }
    
}



// Main Settings Model
/**
 * Main settings model for the Power BI visual formatting pane. Contains all formatting cards and option groups.
 */
export class VisualSettingsModel {
    columnWidth: ColumnWidthCardSetting;
    cards: Array<formattingSettings.SimpleCard | formattingSettings.CompositeCard>;
    constructor() {
      
        this.columnWidth = new ColumnWidthCardSetting();
        this.cards = [
            this.columnWidth
        ];
    }
}

-visual.ts:

this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualSettingsModel, dataView);
      // Dynamically create per-column width cards for the formatting pane using formatted columns
      if (dataView && dataView.matrix) {
        const formatted = formatMatrixForFGGrid(dataView.matrix);
        console.log("Formatted: ", formatted)
        const formattedColumns = formatted.columns || [];
        const fieldWidthCardItems = formattedColumns.map((col: any) => {
          // Use col.index for name and col.title for displayName
          let widthValue = 120;
          if (this.formattingSettings?.columnWidth?.container?.containerItems) {
            const match = this.formattingSettings.columnWidth.container.containerItems.find((item: any) => item.name === col.index);
            if (match && match.width) {
              widthValue = match.width.value;
            }
          }
          return new ColumnWidthCardItem(col.index, col.title, widthValue);
        });
        console.log("fieldWidthCardItems: ", fieldWidthCardItems);
        // Set the containerItems array on the formattingSettings model
        if (this.formattingSettings?.columnWidth?.container) {
          console.log("Updating columnWidth with formatted columns.");
          this.formattingSettings.columnWidth.container.containerItems = [];
          this.formattingSettings.columnWidth.container.containerItems.push(...fieldWidthCardItems);
          console.log("formattingSettings: ", this.formattingSettings);
        }
      }

 

1 Reply

  • a-smiggle 

     

    Settings.ts:

    import powerbi from "powerbi-visuals-api";
    import { formattingSettings, formattingSettingsCard, formattingSettingsTypes } from "powerbi-visuals-utils-formattingmodel";

    // --- Dynamic Column Width Item ---
    export class ColumnWidthCardItem extends formattingSettings.SimpleCard {
    public width: formattingSettings.NumUpDown;

    constructor(name: string, displayName: string, widthValue: number) {
    super();
    this.name = name; // dynamic key
    this.displayName = displayName; // what shows in the formatting pane

    this.width = new formattingSettings.NumUpDown({
    name: "width",
    displayName: "Column Width",
    value: widthValue,
    options: {
    minValue: { type: formattingSettingsTypes.ValidatorType.Min, value: 20 },
    maxValue: { type: formattingSettingsTypes.ValidatorType.Max, value: 1000 },
    },
    });

    // Important: binds this property to the card
    this.slices = [this.width];
    }
    }

    // --- Container Card ---
    export class ColumnWidthCardSetting extends formattingSettings.SimpleCard {
    public container: formattingSettings.Container;

    constructor() {
    super();
    this.name = "columnWidth";
    this.displayName = "Column Width";

    // Initialize empty container for dynamic items
    this.container = {
    displayName: "Apply settings to",
    containerItems: []
    };
    }
    }

    // --- Main Visual Settings Model ---
    export class VisualSettingsModel {
    columnWidth: ColumnWidthCardSetting;
    cards: Array<formattingSettings.SimpleCard | formattingSettings.CompositeCard>;

    constructor() {
    this.columnWidth = new ColumnWidthCardSetting();
    this.cards = [this.columnWidth];
    }
    }

     

    Visual.ts:

    // Populate formatting settings
    this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(
    VisualSettingsModel,
    dataView
    );

    // Only proceed if dataView has matrix data
    if (dataView && dataView.matrix) {
    const formattedColumns = formatMatrixForFGGrid(dataView.matrix).columns || [];

    // Generate dynamic container items per column
    const containerItems = formattedColumns.map((col: any) => {
    // Default width value (can come from previous saved settings)
    let widthValue = 120;

    // Check if a value already exists in formattingSettings
    const match = this.formattingSettings.columnWidth.container.containerItems.find(
    (item: any) => item.name === col.index
    );
    if (match && match.width) {
    widthValue = match.width.value;
    }

    return new ColumnWidthCardItem(col.index, col.title, widthValue);
    });

    // Assign dynamically generated items to the container
    this.formattingSettings.columnWidth.container.containerItems = containerItems;
    }

    // --- OPTIONAL: log to debug ---
    console.log("Dynamic ColumnWidth Settings:", this.formattingSettings);

     

     

    • Each ColumnWidthCardItem has a slices array pointing to its width property.

    • Do not replace the entire formattingSettings object after the visual has been initialized — just update containerItems.

    • populateFormattingSettingsModel must run before rendering the formatting pane, so Power BI knows about the slices.

    • The name of the card item (col.index) is used to track which column the setting belongs to.

    BBF


    💡 Did I answer your question? Mark my post as a solution!

    👍 Kudos are appreciated

    🔥 Proud to be a Super User!