Hi all
I am loosing my mind with this issue - hope anyone can help me.
I have developed a React PCF control that is bound to a SingleLine.Text field. The control takes a string as input (parameter name is "value") and hides the 4 last characters of the string. The control has an associated toggle that can show/hide the last 4 characters of the string.
Here is the ControlManifest.Input.xml file:
<?xml version="1.0" encoding="utf-8" ?>
<manifest>
<control
namespace="FieldAnonymizerComponent"
constructor="FieldAnonymizerComponent"
version="0.0.1"
display-name-key="FieldAnonymizerComponent"
description-key="FieldAnonymizerComponent description"
control-type="virtual"
>
<external-service-usage enabled="false">
</external-service-usage>
<property name="value" display-name-key="value" description-key="value" of-type="SingleLine.Text" usage="bound" required="true" />
<resources>
<code path="index.ts" order="1"/>
<platform-library name="React" version="16.8.6" />
<platform-library name="Fluent" version="8.29.0" />
</resources>
</control>
</manifest>
Here is the index.ts file:
import { IInputs, IOutputs } from "./generated/ManifestTypes";
import AnonymizerComponent, { IAnonymizerComponentProps } from "./AnonymizerComponent";
import * as React from "react";
export class FieldAnonymizerComponent implements ComponentFramework.ReactControl<IInputs, IOutputs> {
private _notifyOutputChanged: () => void;
private _value: string;
private _isReadOnly: boolean;
private _refreshData: (value: string) => void;
constructor() { }
public init(
context: ComponentFramework.Context<IInputs>,
notifyOutputChanged: () => void,
state: ComponentFramework.Dictionary
void {
this._value = context.parameters.value.raw ?? "";
this._isReadOnly = context.mode.isControlDisabled;
this._notifyOutputChanged = notifyOutputChanged;
this._refreshData = this.refreshData.bind(this);
}
public updateView(context: ComponentFramework.Context<IInputs>): React.ReactElement {
const props: IAnonymizerComponentProps = {
value: this._value,
isReadOnly: this._isReadOnly,
refreshData: this._refreshData
};
return React.createElement(
AnonymizerComponent, props
);
}
public refreshData(value: string): void {
this._value = value;
this._notifyOutputChanged();
}
public getOutputs(): IOutputs {
return {
value: this._value
};
}
public destroy(): void { }
}
Here is the React component:
import * as React from 'react';
import { Stack } from '@fluentui/react';
import { useState } from 'react';
import { provideFluentDesignSystem, fluentTextField, fluentSwitch } from '@fluentui/web-components';
import { provideReactWrapper } from '@microsoft/fast-react-wrapper';
import { Constants } from './../constants/constants';
const { wrap } = provideReactWrapper(React, provideFluentDesignSystem());
export const FluenTextField = wrap(fluentTextField());
export const FluentSwitch = wrap(fluentSwitch());
export interface IAnonymizerComponentProps {
value?: string;
isReadOnly: boolean;
refreshData: (value: string) => void;
}
const AnonymizerComponent = (props: IAnonymizerComponentProps) => {
const [isAnonymized, setIsAnonymized] = useState(true);
const [value, setValue] = useState(props.value ?? "");
return (
<Stack horizontal>
<FluenTextField
value={isAnonymized ? anonymize(value) : value}
style={{ width: "100px" }}
onInput={(e: React.FormEvent<HTMLInputElement>) => updateValue(e)}
readOnly={setIsReadOnly()}
maxLength={Constants.MaxCprLength}
/>
<Stack verticalAlign="end">
<FluentSwitch
onClick={() => { isAnonymized ? setIsAnonymized(false) : setIsAnonymized(true) }}
style={{ marginLeft: "10px", marginBottom: "6px" }}
>
<span slot="checked-message" style={{ paddingLeft: "7px" }}>{Constants.ToggleLabel}</span>
<span slot="unchecked-message" style={{ paddingLeft: "7px" }}>{Constants.ToggleLabel}</span>
</FluentSwitch>
</Stack>
</Stack>
)
function updateValue(event: React.FormEvent<HTMLInputElement>): void {
setValue(event.currentTarget.value);
props.refreshData(event.currentTarget.value);
}
function anonymize(value?: string): string {
if (!value) return "";
if (value.length == Constants.MaxCprLength) {
return `${value.slice(Constants.CprSubSetMinValue, Constants.CprSubSetMaxValue)}${Constants.CprAnonymizedSuffix}`
}
return value;
}
function setIsReadOnly(): boolean {
if (props.isReadOnly) return true;
else return isAnonymized;
}
}
export default AnonymizerComponent;
The PCF control works fine when added to a form in a model driven app.
Toggle off:

Toggle on:

However, when I try to add it to a Canvas App and apply the input for the "value" parameter using a variable, like so:

Nothing is shown in the control, even though I know that the variable contains the value "1111111111":

If I provide static value like so:

Then the value is displayed in the control:

I hope I have provided enough information and that someone can help me with this very strange issue. Thanks!