PCF Dataset Control – Lookup Values

After getting over my initial authentication problems, my next adventure with PCF was to show some details from a lookup field in a dataset-bound control.

With a dataset control, the manifest file can contain mappings for the attributes in the dataset that will be shown in the control, e.g.

<manifest>
  <control namespace="MyNameSpace" constructor="MyDatasetControl" version="1.0.0" control-type="dataset">
    <data-set name="dataSet">
      <property-set name="textField" of-type="SingleLine.Text" usage="bound" />
    </data-set>
  </control>
</manifest>

This would allow the control to be configured to show the details from any text field in the dataset. In my case though, I wanted to show the details of a lookup field (specifically the ownerid field). Unfortunately though, the Lookup.* attribute types are not supported, and produce an error during building the control.

As I only actually needed the name of the owner, not the ID, I thought I’d create a calculated field on the entity to take the name of the owning user. However, while calculated fields can take values from related records, the owner details seem to be special and not available.

Next I considered using a Flow to copy the owner’s name into a separate field, but this seemed like overkill. There had to be a better way.

As this was my first dataset-bound PCF control, I assumed that all the columns it was going to use had to be listed in the manifest. However, I’d been over-thinking it. I found that it also has access to all the columns in the view it’s bound to. So as long as the view had the ownerid field I needed, all the data would be available to me anyway.

Rather than hard-code the ownerid field name though, I’d still prefer to make it configurable. To that end I added a simple input type text field so I could enter the field name in the control configuration.

Final Code

After a lot of trial and error trying to find a solution, I ended up with (abbreviated):

Manifest

<manifest>
  <control namespace="MyNameSpace" constructor="MyDatasetControl" version="1.0.0" display-name-key="DemoPcf_Display" description-key="DemoPcf_Description" control-type="standard">
    <data-set name="dataSet" display-name-key="Dataset_Display_Key" />
    <property-set name="fieldName" display-name-key="fieldName_Display" description-key="fieldName_Description" of-type="SingleLine.Text" usage="input" required="true" />
  </control>
</manifest>

Typescript

public init(
    context: ComponentFramework.Context<IInputs>,
    notifyOutputChanged: () => void,
    state: ComponentFramework.Dictionary,
    container: HTMLDivElement,
  ): void {
  this._fieldName = context.parameters.fieldName;
}

public updateView(context: ComponentFramework.Context<IInputs>): void {
  const values = context.parameters.dataSet.sortedRecordIds.map((id) => {
    const record = context.parameters.dataSet.records[id];
    const id = record.getRecordId();
    const lookupName = record.getFormattedValue(_fieldName);
    const lookupValue = <string>record.getValue(_fieldName);

    const value = new Record();
    value.id = id;
    value.user = new User();
    value.user.userId = lookupValue;
    value.user.text = lookupName;

    return value;
  });

  (this.viewModel.values as IObservableArray).replace(values);
}

After adding this to the form I can type in the column I want to show the value from. So long as that column is in the view, the value will be shown correctly.

It’s not perfect, as there’s no validation on the name of the attribute you can type in, or that it exists in the view. Unfortunately, without the ability to create a bound lookup field, I think this is the best we currently have.

I’m really not sure why we can’t bind to lookup fields properly, especially as we can use them when they’re in the view. Hopefully this will come in time 🤞

Leave a comment

Your e-mail address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.