Recently, I’ve been finally diving into PCF (Power Apps Component Framework) development. One of the first controls I’ve built was a React checkbox control with tooltips for a multi select option set as I wanted to have a replacement for the ugly combo box that Microsoft provides us as the only default option for this type of attribute.

To my surprise, pairing the custom control with client scripts triggered by events on a form was not as straightforward as I expected. Let me share with you my findings.

Methods for choice(s) controls

The Client API offers quite a few methods to interact with controls on a form. Multi select option sets are no exception (see the docs here).

Client API methods for choice(s) controls

Methods such as setVisible or setDisabled are common for almost all controls. These work as expected, as long as your component reacts to the context properties (for example, your control should react to the isControlDisabled property from the context, and enable/disable the control accordingly).

Disabled checkbox control

Issue with choice(s) specific methods

Then we have a group of methods for choice controls that can dynamically change the options offered to the user such as: addOption, removeOption and clearOptions. Unexpectedly, these methods do not work for the custom control as they normally do for the default combo box control from Microsoft (I tried both the formContext and deprecated Xrm.Page objects inside a client form script as well).

Default combo box control: Default combo box control

Custom control: Client script error

It seems to me that Microsoft simply forgot to add these methods to the multi select custom control objects. Out of a curiosity, I’ve tried to run the same methods on a single select option set PCF and they worked as expected.

Single select option set PCF

This behavior appears to be a limitation in Microsoft’s implementation.

Workaround

We cannot use the choices specific methods directly with the custom multi select PCF controls for now. However, as the methods work fine with the default combo box control, we can take advantage of this to implement a workaround.

If we modify the options of the default combo box control using client script methods as shown above, the available options inside the context of the custom control are also updated as long as both controls are bound to the same attribute.

Script that modifies the options of the default combo box control

We can simply hide the default combo box control on the form and refer to it in the client scripts. This way, we can dynamically modify the options of the custom control.

Working example

// Client script used in the example above.
var Sdk = window.Sdk || {};
(function() {
    /**
     * Trigger: On form load
     * @param {Object} executionContext - The execution context of the form.
     */
    this.onLoad = function(executionContext) {
        this.filterLevel(executionContext);
    };

    /**
     * Trigger: On form load or on change of the "pivny_firstyearcourse" attribute
     * Description: Filters the options of the level control based on the value of the first year course attribute.
     * @param {Object} executionContext - The execution context of the form.
     */
    this.filterLevel = function(executionContext) {
        const formContext = executionContext.getFormContext();
        const firstYearLevels = [
            { value: 1000, text: "Undergraduate" }
        ]
        const nonFirstYearLevels = [
            { value: 1000, text: "Undergraduate" },
            { value: 1100, text: "Graduate" },
            { value: 1300, text: "Postgraduate" }
        ]
        const isFirstYear = formContext.getAttribute("pivny_firstyearcourse").getValue();
        const levelControl = formContext.getControl("pivny_level1"); //Default combo box control
        levelControl.clearOptions(); 
        switch (isFirstYear) {
            case true:
                firstYearLevels.forEach(level => {
                    levelControl.addOption(level);
                });
                break;
            case false:
                nonFirstYearLevels.forEach(level => {
                    levelControl.addOption(level);
                });
                break;
            default:
                console.warn(`Unexpected value for isFirstYear: ${isFirstYear}`);
                break;
        }
    };

    /**
     * Trigger: On change of the "pivny_level" attribute
     * Description: Clears the current values of the "pivny_level" attribute.
     * @param {Object} executionContext - The execution context of the form.
     */
    this.clearLevelValues = function(executionContext) {
        const formContext = executionContext.getFormContext();
        formContext.getAttribute("pivny_level").setValue();
    }
    
}).call(Sdk);

Conclusion

PCFs are an excellent way to enhance the user experience in Power Apps (particularly Model Driven Apps), in scenarios where Microsoft’s out-of-the-box offerings fall short. However, when implementing custom controls for multi select option sets, be cautious as some Client API methods triggered by form events don’t function as expected - it appears these capabilities were overlooked in the implementation. This post demonstrates a straightforward workaround to address this limitation, by interacting with the default combo box control from Microsoft. The other workaround that comes to my mind is to implement own event handlers that would be bound to the window.parent object, but that requires a bit more work to be done.

For anyone interested in the checkbox control displayed in this article, I’ve shared the repo on GitHub.