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 🤞
Cool Thanks! ..Going to try it out
change this:
to this: