LWC Community – Dynamic Picklist Property Causing Rendering Error on Community Record Page

community-builderdesign-attributeserrorlightning-communitylightning-web-components

I've a custom LWC (Lightning Web Component) built to be used for a community (or Digital Experience). The component can be put on a Home Page or a Community Record Page.

I've few properties that within Community Builder can be set while publishing the component in the community.

These properties when set makes the component cause this error:
Community component rendering error

This error only occurs when I chose to select a value from Identifier property, if I leave it empty then it works and displays fine.

This is how my test component rendering when I keep Identifier value as empty selection:
enter image description here

Here is the component code:

myCommunityCmp.html

<template>
    recordId: {recordId}<br/>
    objectApiName: {objectApiName}<br/>
    identifier: {identifier}<br/>
</template>

myCommunityCmp.js

import { LightningElement, api, track, wire } from "lwc";

export default class MyCommunityCmp extends LightningElement {
    @api recordId;      //current context > record id
    @api objectApiName; //current context > sObject API Name
    @api identifier;
    
    connectedCallback() {
        console.log('Connected Callback');
    }
    renderedCallback() {
        console.log('Rendered Callback');
    }
    errorCallback(error, stack) {
        console.log('error callback', error);
        console.log('error callback [stack]', stack);
    }
}

myCommunityCmp.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <masterLabel>Custom Community Cmp</masterLabel>
    <isExposed>true</isExposed>
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightningCommunity__Default">
            <property name="identifier" type="String" datasource="apex://IdentifierController" label="Identifier" default="" description="Enter a unique value to differentiate this instance from others on the page"/>
            <property name="recordId" type="String" label="Record Id" description="Automatically bind the page's record id to the component variable" default="{!recordId}" />
            <property name="objectApiName" type="String" label="Object Name" description="Automatically bind the page's object name to the component variable" default="{!objectApiName}" />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

APEX Class to generate Identifier picklist values:
IdentifierController.cls

global class IdentifierController extends VisualEditor.DynamicPickList {
    VisualEditor.DesignTimePageContext context;
    global IdentifierController(VisualEditor.DesignTimePageContext context) {
        this.context            = context;
    }

    global override VisualEditor.DataRow getDefaultValue(){
        /*VisualEditor.DynamicPickListRows values = getValues();
        if (values != null && values.size() > 0) {
            return values.get(0);
        }
        return null;*/
        return new VisualEditor.DataRow('-- Pick a value here --', '');
    }
    
    global override VisualEditor.DynamicPickListRows getValues() {
        VisualEditor.DynamicPickListRows  myValues  = new VisualEditor.DynamicPickListRows();
        myValues.addRow( new VisualEditor.DataRow('-- Pick a value here --', '') );
        String identifierId     = 'BE-';
        if (context != null) {
            if (!String.isBlank(context.entityName)) {
                identifierId        += Schema.getGlobalDescribe().get(context.entityName).getDescribe().getLabel();
            }
            if (!String.isBlank(context.pageType)) {
                identifierId        += context.pageType;
            }
            identifierId            = identifierId.trim().replaceAll('(\\s+)', '');
        }
        for (integer i=0; i<15; i++) {
            string picklistValue = identifierId + '-' + (i+1);
            myValues.addRow( new VisualEditor.DataRow(picklistValue, picklistValue) );
        }
        return myValues;
    }
}

The steps to reproduce are simple:

  • Have a Community and generate Object Pages for an object, say, Contact object.
  • Switch to Contact Detail community page within Community Builder.
  • Put this LWC Component on the Page anywhere.
  • The component will render without any issue, all the Console.log calls are called in browser console.
  • Select the component and in component properties dialog change Identifier picklist to any value.
  • The component will now fail to render, and notice that connectedCallback, renderedCallback, or errorCallback – none will be called. There would be nothing in the Debug Logs as well pointing to any error of any kind.

The code seems very simple to me, doesn't look like it should cause any error, but I'm unable to get past this issue. Could this be a Potential Community Bug?

Best Answer

Definitely looks like a bug.

It does not fail for me in Home page, as the context does not return any information for the picklist, so the picklist values are always the same

In record pages, it uses the context to build the picklist like 'BEContactCommRecordPage1, BEContactCommRecordPage2...' etc values.

When you change the identifier value, the getValues() method is called again to build again the picklist, and suddenly the values returned are not the same as before, because the context is null:

DesignTimePageContext:[entityName=null, pageType=null]

Before, it was not null

DesignTimePageContext:[entityName=Contact, pageType=CommRecordPage]

I tried everything to avoid getValues() to be called each time I change the 'identifier' value, and here is the solution; Implement an override for isValid():

global override boolean isValid(Object attr) {
    return true;
}

This will avoid to call getValues() each time you change.

Source: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_config_for_app_builder_dynamic_picklists.htm

Another possible but ugly solution is to build these identifiers with custom metadata so that they are not built dynamically but hard coded, and then choose each identifier for each component on purpose (as I guess this should be an admin task)

Related Topic