web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Customer experience | Sales, Customer Insights,...
Suggested answer

Problem with onChange of FluentUI TestField inside PCF as virtual control

(0) ShareShare
ReportReport
Posted on by 40

Hi,

Pretty new to PCF and React, I'm more an angular guy ;-)

Goal is to create a password control PCF, simply masking the input for the enduser.

Because I want it to look like a standard control, I decided to use a React/FluentUI and it's TextField.

Also using the new virtual control feature to have a more optimal package size.

Problem is on the onChange hook, my control does not generate in the sandbox with following message :The error "Invalid hook call. Hooks can only be called inside the body of a function component" occurs for multiple reasons ..."

I made sure that my react version is the same as the one specified as platform-library in the manifest file.

Couldn't find any real life examples of the use of a TextField that is bound to a value :-(

This is my control.tsx file :

export interface IPasswordInputControlClassProps {
    context: ComponentFramework.Context<IInputs>;
    value?: string;
    onChange: (newValue?: string) => void;
}
export class PasswordInputControlClass extends React.Component<IPasswordInputControlClassProps> {

    onChange = React.useCallback(
        (ev: React.FormEvent<HTMLInputElement|HTMLTextAreaElement>,newValue?: string) => {            
            if (this.props.onChange) {
                this.props.onChange(newValue);
            }
        },
        [this.props.value]
    );

  public render(): React.ReactNode {
    return (
      <TextField type="password" styles={textFieldStyle} placeholder='---' value={this.props.value} onChange={this.onChange}/>
    )
  }
}

And this is my index.ts :

export class PasswordInputControl implements ComponentFramework.ReactControl<IInputs, IOutputs> {
    private theComponent: ComponentFramework.ReactControl<IInputs, IOutputs>;
    private notifyOutputChanged: () => void;

    _currentValue: string | undefined;

    /**
     * Empty constructor.
     */
    constructor() { }

    /**
     * Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
     * Data-set values are not initialized here, use updateView.
     * @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
     * @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
     * @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
     */
    public init(
        context: ComponentFramework.Context<IInputs>,
        notifyOutputChanged: () => void,
        state: ComponentFramework.Dictionary
    ): void {
        this.notifyOutputChanged = notifyOutputChanged;
    }

    /**
     * Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
     * @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
     * @returns ReactElement root react element for the control
     */
    public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
        console.log("entered UpdateView", context.updatedProperties);
        debugger;
        this._currentValue = context.parameters.value.raw ?? undefined;
        const props: IPasswordInputControlClassProps = { value: this._currentValue , context: context, onChange: this.onChangeValue.bind(this) };
        return React.createElement(
            PasswordInputControlClass, props
        );
    }

    /**
     * It is called by the framework prior to a control receiving new data.
     * @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”
     */
    public getOutputs(): IOutputs {
        return {
            value: this._currentValue ?? ''
        };
    }

    /**
     * Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
     * i.e. cancelling any pending remote calls, removing listeners, etc.
     */
    public destroy(): void {
        // Add code to cleanup control if necessary
    }

    private onChangeValue(newValue?: string) {
        this._currentValue = newValue;
        if (this.notifyOutputChanged) {
            this.notifyOutputChanged();
        }
    }
}

I have the same question (0)
  • Sven Peeters Itineris Profile Picture
    40 on at
    RE: Problem with onChange of FluentUI TestField inside PCF as virtual control

    Hi,

    First of all, thank you very much for the feedback, highly appreciated.

    Unfortunately none of the pcf controls you mentioned are of the new 'virtual' type.

    And that's just what I'm trying to use as this is the new/better way to create pcf controls.

    If I use the React.memo approach, it works more or less. However when I type very quickly, it skips some keys :-(

    export const PasswordInputControlClass = React.memo((props:IPasswordInputControlClassProps): JSX.Element => {

       const onTextChanged = (event: any, newValue?: string) => {              

           props.onChange(newValue);          

         }

       return (<TextField type="password" styles={textFieldStyle} placeholder='---' value={props.value} onChange={onTextChanged}/>);

    }

    Using the approach that microsoft uses when it constructs the project, I'm stuck with the invalid hook error.

    Bizarly enough, I cannot find ANY example using a hook combined with the class approach

    export class PasswordInputControlClass extends React.Component<IPasswordInputControlClassProps> {

       onChange = React.useCallback(

           (ev: React.FormEvent<HTMLInputElement|HTMLTextAreaElement>,newValue?: string) => {            

               if (this.props.onChange) {

                   this.props.onChange(newValue);

               }

           },

           [this.props.value]

       );

     public render(): React.ReactNode {

       return (

         <TextField type="password" styles={textFieldStyle} placeholder='---' value={this.props.value} onChange={this.onChange}/>

       )

     }

    }

    Regards,

    Sven Peeters

  • Suggested answer
    Community Member Profile Picture
    on at
    RE: Problem with onChange of FluentUI TestField inside PCF as virtual control

    Hi Sven,

    In PCF Gallery, there are some existing control you can used to mask input in the field, maybe you can try to use them to achieve you goal directly.

    https://pcf.gallery/categories#masked%20input 

    pastedimage1663309711740v1.png

    Or you can refer the following blog to create custom password PCF component:

    https://betterprogramming.pub/creating-custom-password-pcf-component-for-the-power-platform-591ab6645b28 

    For the error you met, you may refer the following links

    https://bobbyhadz.com/blog/react-invalid-hook-call-hooks-can-only-be-called-inside-body

    https://github.com/vercel/next.js/issues/7626

    github.com/.../15315

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Andrés Arias – Community Spotlight

We are honored to recognize Andrés Arias as our Community Spotlight honoree for…

Leaderboard > Customer experience | Sales, Customer Insights, CRM

#1
DAnny3211 Profile Picture

DAnny3211 134

#2
Daniyal Khaleel Profile Picture

Daniyal Khaleel 106

#3
Abhilash Warrier Profile Picture

Abhilash Warrier 70 Super User 2025 Season 2

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans