Forum Discussion

cogsie's avatar
cogsie
Helper I
6 years ago
Solved

Format Panel Toggle Switch to Reveal More Options

In a custom visual, is it possible to create a sub-section in the format panel that will appear or disappear when a toggle is switched?

 

For example, in the standard bar chart visual under the "Data Labels Section" there is a "show background" option. 

 

 

 

 
 

When you click on that it causes several more options to appear that weren't previously there:

 

 

I would like to duplicate this on a custom visual.  I tried modifying the capabilities file in all different ways (especially using the show function) but couldn't figure it out.  Any suggestions?

 

  • Hi cogsie,

    The way this works is by elmination:

    • Properties have to exist in the visual capabilities first.
    • They can be removed from view in your object enumeration logic.

    You can get quite creative with it, but I'll provide a simple example.

    First ensure that your objects are all configured up in your capabilities.json and they have a corresponding setting object so that they appear in the pane.

    If we start with a new visual, I've added these to the capabilities under the dataPoint object:

    "toggle": {
        "displayName": "Show my Property",
        "type": {
            "bool": true
        }
    },
    "hideOnToggle": {
        "displayName": "I Get Hidden if This Works",
        "type": {
            "text": true
        }
    }

    I'll add a couple of extra properties to the dataPointSettings class in settings.ts, e.g.:

          ...
          // Test toggle
          public toggle: boolean = true;
          // Should hide if toggle off
          public hideOnToggle: string = 'Hiya!';
       }

    These should now show up in my properties pane, e.g.:

    I'll now wire-up my logic.

    • You can then change enumerateObjectInstances in visual.ts to manipulate the object that gets returned to the properties pane.
    • This runs once for every menu in the pane that you have configured, so you need to check which one is currently being processed and handle accordingly.

    To make this easier we can change the function a little bit. Assuming you're starting with the one that gets generated, first change its signature to:

        public enumerateObjectInstances(
            options: EnumerateVisualObjectInstancesOptions
        😞 VisualObjectInstance[] {
    
            const instances: VisualObjectInstance[] = (
                VisualSettings.enumerateObjectInstances(
                    this.settings || VisualSettings.getDefault(),
                    options
                ) as VisualObjectInstanceEnumerationObject).instances;
            
            return instances;
    
        }

    This gets the same result as before, but exposes the current instance being processed, so that you can manipulate it. We'll now add some logic to process the pane, e.g.:

        public enumerateObjectInstances(
            options: EnumerateVisualObjectInstancesOptions
        😞 VisualObjectInstance[] {
    
            const instances: VisualObjectInstance[] = (
                VisualSettings.enumerateObjectInstances(
                    this.settings || VisualSettings.getDefault(),
                    options
                ) as VisualObjectInstanceEnumerationObject).instances;
            
            /** 
             * This will be the name of our current menu and will match the 
             * object name from capabilities
             */
                let objectName = options.objectName;
    
            /**
             * Process the object, based on which one it is
             */
                switch (objectName) {
    
                    case 'dataPoint': {
                        /**
                         * Handle toggle of our text field by removing it from view.
                         */
                            if (!this.settings.dataPoint.toggle) {
                                delete instances[0].properties['hideOnToggle'];
                            }
                            break;
                    }
    
                    /** Add logic for additional menus underneath as needed */
    
                }
    
            return instances;
    
        }

    This will now remove the text box when we toggle to false and leave it in as intended when we toggle to true, e.g.:

    Note that this does not change the actual settings in the visual and simply manages what gets returned to the main window to present to the user. You can still access the underlying settings for the hidden items in your visual logic and you need to plan for this in some cases.

    For example, if our text field has some influence on our visual (e.g. a displayed label), then you would need to handle what happens if the toggle is off, so that the underlying value does not get shown anyway.

    As mentioned above, you can get very creative with this and can use a number of different conditions, and also use properties in one menu to hide those in another. If you check the source of other custom visuals you should be able to see examples of how other authors are doing it.

    I hope this gets you moving. Good luck!

    Daniel

3 Replies

  • dm-p's avatar
    dm-p
    Super User

    Hi cogsie,

    The way this works is by elmination:

    • Properties have to exist in the visual capabilities first.
    • They can be removed from view in your object enumeration logic.

    You can get quite creative with it, but I'll provide a simple example.

    First ensure that your objects are all configured up in your capabilities.json and they have a corresponding setting object so that they appear in the pane.

    If we start with a new visual, I've added these to the capabilities under the dataPoint object:

    "toggle": {
        "displayName": "Show my Property",
        "type": {
            "bool": true
        }
    },
    "hideOnToggle": {
        "displayName": "I Get Hidden if This Works",
        "type": {
            "text": true
        }
    }

    I'll add a couple of extra properties to the dataPointSettings class in settings.ts, e.g.:

          ...
          // Test toggle
          public toggle: boolean = true;
          // Should hide if toggle off
          public hideOnToggle: string = 'Hiya!';
       }

    These should now show up in my properties pane, e.g.:

    I'll now wire-up my logic.

    • You can then change enumerateObjectInstances in visual.ts to manipulate the object that gets returned to the properties pane.
    • This runs once for every menu in the pane that you have configured, so you need to check which one is currently being processed and handle accordingly.

    To make this easier we can change the function a little bit. Assuming you're starting with the one that gets generated, first change its signature to:

        public enumerateObjectInstances(
            options: EnumerateVisualObjectInstancesOptions
        😞 VisualObjectInstance[] {
    
            const instances: VisualObjectInstance[] = (
                VisualSettings.enumerateObjectInstances(
                    this.settings || VisualSettings.getDefault(),
                    options
                ) as VisualObjectInstanceEnumerationObject).instances;
            
            return instances;
    
        }

    This gets the same result as before, but exposes the current instance being processed, so that you can manipulate it. We'll now add some logic to process the pane, e.g.:

        public enumerateObjectInstances(
            options: EnumerateVisualObjectInstancesOptions
        😞 VisualObjectInstance[] {
    
            const instances: VisualObjectInstance[] = (
                VisualSettings.enumerateObjectInstances(
                    this.settings || VisualSettings.getDefault(),
                    options
                ) as VisualObjectInstanceEnumerationObject).instances;
            
            /** 
             * This will be the name of our current menu and will match the 
             * object name from capabilities
             */
                let objectName = options.objectName;
    
            /**
             * Process the object, based on which one it is
             */
                switch (objectName) {
    
                    case 'dataPoint': {
                        /**
                         * Handle toggle of our text field by removing it from view.
                         */
                            if (!this.settings.dataPoint.toggle) {
                                delete instances[0].properties['hideOnToggle'];
                            }
                            break;
                    }
    
                    /** Add logic for additional menus underneath as needed */
    
                }
    
            return instances;
    
        }

    This will now remove the text box when we toggle to false and leave it in as intended when we toggle to true, e.g.:

    Note that this does not change the actual settings in the visual and simply manages what gets returned to the main window to present to the user. You can still access the underlying settings for the hidden items in your visual logic and you need to plan for this in some cases.

    For example, if our text field has some influence on our visual (e.g. a displayed label), then you would need to handle what happens if the toggle is off, so that the underlying value does not get shown anyway.

    As mentioned above, you can get very creative with this and can use a number of different conditions, and also use properties in one menu to hide those in another. If you check the source of other custom visuals you should be able to see examples of how other authors are doing it.

    I hope this gets you moving. Good luck!

    Daniel

    • cogsie's avatar
      cogsie
      Helper I

      That worked perfectly.  I was trying to tinker around with the settings.ts file, but obviously that was not working.  I would never have figured this out.  Thanks for the help.

      • dm-p's avatar
        dm-p
        Super User
        No worries - it's not intuitive at all so if I can save at least one person the majority of the time it took me, then that's a win in my book!