Forum Discussion

ViDuong's avatar
ViDuong
Frequent Visitor
8 months ago

VisualUpdate doesn't trigger in custom visual when switching from reading to edit mode

I am having the following problem:
Previously, I used dataViewMapping as TABLE and it worked fine.
But after I used dataViewMapping MATRIX instead of TABLE, it did not trigger the update function when I switched from viewmode to editmode, it only triggered the update function when I zoomed in/out of the viewport, or dragged data into visualization, and when I saved the data, saved it to persist, it did not trigger the update function.

public update(options: VisualUpdateOptions) {
    this.countRender++;
    this.viewMode = options.viewMode;
    this.events.renderingStarted(options);
    const dataView = options.dataViews?.[0];
    if (!dataView?.matrix) {
      this.dataOriginal = undefined;
      if (this.countRender > 3) this.clearNodePositions();
      this.countRender = 0;
      this.renderUI();
      return;
    }
    this.formattingSettings =
      this.formattingSettingsService.populateFormattingSettingsModel(
        VisualSettingsModel,
        dataView
      );

6 Replies

  • Hi ViDuong ,

    Thanks for posting in Microsoft Fabric Community.
    When a custom visual uses matrix dataViewMapping, switching between Reading and Edit mode may not always trigger an update, since the host might not rebuild the dataView during that action unless something in the data or layout has changed.

     

    Others have observed similar behaviour, so this might be how the platform currently handles mode transitions. Because of this, the update function may only run after actions such as resizing the visual or modifying fields.

     

    Similar cases and related discussions were discussed here:
    Visual.update() not triggered when switching from ... - Microsoft Fabric Community

    Re: VisualUpdate doesn't fire in custom visual whe... - Microsoft Fabric Community

    Visual update doesn't fire when switching from reading to edit view · Issue #401 · microsoft/PowerBI-visuals-tools

     

    If you feel this behaviour might not be expected, you can raise it through the Power BI Issues page for further review:
    Issues - Microsoft Fabric Community

     

    Hope this helps. Please reach out for further assistance.

    Thank you.

      • v-veshwara-msft's avatar
        v-veshwara-msft
        Community Support

        Hi ViDuong ,

        Thanks for the update.

        Just to add one more detail that came up in this related discussion: Re: Visual.update() not triggered when switching f... - Microsoft Fabric Community its noted that this behaviour might only appear when the report is viewed in Actual Size mode. In other view modes, switching between Reading and Edit may trigger a resize event, which then causes the visual to receive an update with the mode flag included.

         

        You may want to check whether the mode works differently when the report is not in Actual Size, as this might help validate the workaround you are testing.

        Feel free to share your observations once you try it.

        Thank you.

  • Hi ViDuong,

    When switching between reading mode and edit mode Power BI doesn't always trigger the update() method for matrix based visuals this happens because:

    • TABLE mapping creates a new dataView when mode changes

    • MATRIX mapping often reuses the same dataView object
    • Power BI optimizes by not calling update() if it thinks the data hasnt changed

    First Approach:Force Update Using View Mode Change Events

    • Add view mode change detection in your visual:
    export class YourVisual implements IVisual {
        private host: IVisualHost;
        private currentViewMode: ViewMode;
        
        constructor(options: VisualConstructorOptions) {
            this.host = options.host;
            
            // Listen for view mode changes
            this.host.viewModeChanged.subscribe((viewMode: ViewMode) => {
                this.currentViewMode = viewMode;
                // Force a re-render when view mode changes
                this.handleViewModeChange();
            });
        }
        
        public update(options: VisualUpdateOptions) {
            this.currentViewMode = options.viewMode;
            // ... your existing update logic
        }
        
        private handleViewModeChange() {
            // Manually trigger UI updates for edit mode
            if (this.currentViewMode === ViewMode.Edit) {
                this.renderEditModeUI();
            } else {
                this.renderReadModeUI();
            }
        }
    }

     

    Second Approach:Use EnumerateObjects to Force Data Refresh

    • Modify your capabilities to include objects enumeration:
    {
        "objects": {
            "general": {
                "properties": {
                    "viewModeToggle": {
                        "type": {
                            "bool": true
                        }
                    }
                }
            }
        }
    }
    •  Then in your update method:
    public update(options: VisualUpdateOptions) {
        this.countRender++;
        this.viewMode = options.viewMode;
        this.events.renderingStarted(options);
        
        // Force enumerate objects to trigger updates
        if (options.viewMode === ViewMode.Edit) {
            this.host.persistProperties({
                merge: [{
                    objectName: "general",
                    properties: {
                        viewModeToggle: this.viewMode === ViewMode.Edit
                    },
                    selector: null
                }]
            });
        }
        
        const dataView = options.dataViews?.[0];
        // ... rest of your code
    }

     

    Third Approach:Check for Mode Specific Changes in Update

    • Enhance your update method to detect mode changes:
    public update(options: VisualUpdateOptions) {
        this.countRender++;
        
        // Check if view mode actually changed
        const viewModeChanged = this.viewMode !== options.viewMode;
        this.viewMode = options.viewMode;
        
        this.events.renderingStarted(options);
        const dataView = options.dataViews?.[0];
        
        if (!dataView?.matrix) {
            this.dataOriginal = undefined;
            if (this.countRender > 3) this.clearNodePositions();
            this.countRender = 0;
            this.renderUI();
            return;
        }
        
        this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(
            VisualSettingsModel,
            dataView
        );
        
        // Always render on mode change, even if data appears unchanged
        if (viewModeChanged) {
            this.renderUI();
            return;
        }
        
        // ... your existing data processing logic
    }

     

    Bonus Approach:Use Update Types

    • Leverage the type property in VisualUpdateOptions:
    public update(options: VisualUpdateOptions) {
        // Check the update type
        if (options.type === VisualUpdateType.ViewModeChange) {
            // Force complete re-render
            this.forceFullRender = true;
        }
        
        // ... your existing code
        
        if (this.forceFullRender || !dataView?.matrix) {
            this.forceFullRender = false;
            this.renderUI();
            return;
        }
    }

     

    if this post helps, then I would appreciate a thumbs up and mark it as the solution to help the other members find it more quickly.