+ Start a Discussion
Moshe BaitelmanMoshe Baitelman 

Adding Lightning component breaks community builder

I have a custom lightning component. It works fine in almost all instances I choose to use it. The functionality is fine. It works in apps, on record page, etc.

When I add the component to the layout of a communities page in the Community Builder, the builder breaks.

This happens before the Init handler is called and everything works when I use lightning app builder so it is unrelated to the controller but I have included that code as well.

To Replicate:
Go to Communities > Choose a community builder > Create a new page (any layout) > Add in the Custom Component (code shown below).

The moment you do so, the container where you placed the component disappears and cannot be reached again. This means I am unable to make changes to the design resources, delete the component, move the component, etc.

Can't figure out for the life of me why. Salesforce error on reload is highly uninformative.

Before adding component:
Before adding componentAfter adding component:
User-added imageAfter page reload:
After reload
Component Code:
<aura:component
        description="PriorityOrdersList"
        implements="force:appHostable,flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes,lightning:availableForFlowScreens"
        access="global"
        controller="priorityOrdersListController"
>

    <!-- handlers-->
    <aura:handler name="init" value="{! this }" action="{! c.init }"/>
    <aura:handler name="modalClosed" event="c:rsModalClosed" action="{!c.onModalClosed}"/>

    <!-- attributes -->
    <aura:attribute
            name="listStatus"
            type="String"
            access="public"
            default="Waiting"
    />
    <aura:attribute
            name="orderData"
            access="private"
            type="Object"
    />
    <aura:attribute
            name="columns"
            type="List"
            access="private"
    />
    <aura:attribute
            name="sortOrder"
            type="String"
            required="true"
            default="rw_Priority__c"
    />
    <aura:attribute
            name="urlSeed"
            type="String"
            required="true"
            default="https://rlscn.force.com/WMS/s/packing"
    />
    <aura:attribute
            name="isLoading"
            type="Boolean"
            access="private"
            default="true"
    />
    <aura:attribute
            name="isModalOpen"
            type="boolean"
            access="private"
            required="false"
    />
    <aura:attribute
            name="modalMessage"
            type="string"
            access="private"
            required="false"
    />

    <lightning:card class="slds-card__body slds-card__body_inner">

        <div style="height: 200px;">
            This is here just to give height to the component and create visibility.
        </div>

        <aura:if isTrue="{! not(v.isLoading) }">
            <aura:if isTrue="{!v.orderData}">
                <!-- the container element determines height of the datatable -->
                <h1 class="slds-m-vertical_small">Orders to fulfill (temporary interface)</h1>

                <lightning:button label="Refresh List" onclick="{! c.refreshOrders}" iconName="utility:refresh"
                                  iconPosition="right"/>

                <div style="height: auto">
                    <lightning:datatable
                            columns="{! v.columns }"
                            data="{! v.orderData }"
                            keyField="Id"
                            hideCheckboxColumn="true"
                            onrowaction="{! c.handleRowAction }"/>
                </div>

                <aura:set attribute="else">
                    <div class="slds-box slds-p-around_small slds-m-vertical_medium">
                        <i>Hooray! You've fulfilled all the orders!</i>
                    </div>
                </aura:set>

            </aura:if>
            <aura:set attribute="else">
                <lightning:spinner variant="brand" size="medium" alternativeText="Loading..."/>
            </aura:set>


        </aura:if>


    </lightning:card>

    <!-- Only display Modal if there is not a blocking operation taking place. -->
    <c:rsModal aura:id="modal" isOpen="{!v.isModalOpen}">
        <aura:unescapedHtml value="{!v.modalMessage}"/>
    </c:rsModal>

</aura:component>
({
    init: function (cmp, event, helper) {

        cmp.set('v.columns', [
            {label: 'Order', fieldName: 'Name'},
            {label: 'Customer', fieldName: 'Account_Owner_for_Sharing_2__c'},
            {label: 'Brand ', fieldName: 'Brand_RL__c'},
            {label: 'Order Number', fieldName: 'rw_Customer_Order__c'},
            {label: 'Priority', fieldName: 'rw_Priority__c'},
            {label: 'Order Date', fieldName: 'Order_Date__c'},
            {
                label: 'Fulfill', type: 'button',
                typeAttributes: {
                    label: 'Fulfill',
                    name: 'fulfill',
                    title: 'Click to fulfill this order',
                    disabled: {fieldName: 'unfillable'}
                }
            }
        ]);

        if (cmp.get("v.listStatus") == 'Waiting') {
            helper.getOrders(cmp);
        } else {
            let message = 'Unknown error';
            console.log(message + ': Did not call for orders.');
        }
    },
    refreshOrders: function (cmp, event, helper) {
        cmp.set("v.isLoading", true);
        helper.getOrders(cmp);
    },

    handleRowAction: function (cmp, event, helper) {
        var action = event.getParam('action');
        var row = event.getParam('row');

        switch (action.name) {
            case 'fulfill':
                helper.launchScanner(cmp, row.Id);
                helper.disableRow(cmp, row);
                break;
        }

    },


    // To Close Modal
    onModalClosed: function (cmp, event, helper) {
        cmp.set('v.modalMessage', null);
        cmp.set('v.isModalOpen', false);
    }
});

Component Helper
{
    getOrders: function (cmp) {
        var helper = this;
        var action = cmp.get('c.getOrderPriorityList');
        var sortOrder = cmp.get('v.sortOrder');

        action.setParams({sortOrder: sortOrder});
        action.setCallback(helper, function (response) {
            var state = response.getState();
            if (state === "SUCCESS") {

                var orderList = response.getReturnValue();

                if(orderList.length > 0) {

                    var rows = response.getReturnValue();     //storing the response in a temporary variable
                    //looping through each row of the result
                    for (var i = 0; i < rows.length; i++) {
                        var row = rows[i];
                        // data columns with relationship __r can not be displayed directly in data table, so generating dynamic columns
                        row.unfillable = false;
                    }

                    orderList = response.getReturnValue();
                    cmp.set("v.orderData", orderList);
                }

            } else if (state === "ERROR") {
                let errors = response.getError();
                let message = 'Unknown error'; // Default error message
                // Retrieve the error message sent by the server
                if (errors && Array.isArray(errors) && errors.length > 0) {
                    message = errors[0].message;
                }
                // Display the message
                this.alert(
                    cmp,
                    'Error Fetching Data',
                    message,
                    'error',
                    false
                );
            } else {
                console.log("Failed with state: " + state);
            }
            cmp.set("v.isLoading", false);
            cmp.set("v.listStatus", 'DataReady')
        });

        // Send actions to be executed
        $A.enqueueAction(action);

    },
    
    launchScanner: function (cmp, orderId) {
        var pageUrl = cmp.get("v.urlSeed");
        window.open(pageUrl + "?recordId=" + orderId);
    },
    disableRow: function(cmp, row) {
        var data = cmp.get('v.orderData');
        var rowIndex = data.indexOf(row);
        data[rowIndex].unfillable = true;
        cmp.set('v.orderData', data);
    },


    getModalCmp: function(cmp, isRequired) {
        return this.getCmp(cmp, 'modal', isRequired);
    },
    getCmp: function(cmp, auraId, isRequired) {
        if(isRequired === undefined) { isRequired = true; }
        var output = cmp.find(auraId);

        if(isRequired && !output) {
            throw new Error('Could not find component with Aura ID: '+auraId);
        }

        return output;
    },


    alert: function(cmp, title, message, theme, hideCloseButton) {
        var modalCmp = this.getModalCmp(cmp);

        if(hideCloseButton === undefined) {
            hideCloseButton = false;
        }

        if(modalCmp) {
            var messageEscaped = this.escapeHtml(message);
            var messageHtml = messageEscaped.replace(/\n/g, '<br />');

            cmp.set('v.isModalOpen', false);
            cmp.set('v.modalMessage', messageHtml);
            modalCmp.set('v.hideDefaultCloseControls', hideCloseButton);
            modalCmp.set('v.variant', 'alert');
            modalCmp.set('v.title', title);
            modalCmp.set('v.theme', theme || 'default');
            cmp.set('v.isModalOpen', true);
        } else {
            cmp.set('v.modalMessage', message);
            alert(message);
        }

    },

    escapeHtml: function(text) {

        // Copied from://stackoverflow.com/a/4835406

        var map = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#039;'
        };

        return text.replace(
            /[&<>\x22\x27]/g,
            function(m) { return map[m]; }
        );
    }
})

Design
<design:component>
    <design:attribute name="sortOrder" description="Fields by which to sort the orders"
                      default="Order_Date__c, rw_Priority__c" required="true" label="Sort ORDER BY" />
    <design:attribute name="urlSeed" description="URL to append the RecordID to when initiating the packing interface"
                      default="https://rlscn.force.com/WMS/s/packing" required="true" label="Base URL" />
</design:component>


Apex Controller
public with sharing class priorityOrdersListController {

    @AuraEnabled
    public static List<rw_Shipment__c> getOrderPriorityList(String sortOrder) {

        try {
            String queryString = 'SELECT Id, Name, rw_Status__c, Warehouse_Status__c, CreatedDate, ' +
                    'Account_Owner_for_Sharing_2__c, Brand_RL__c, Brand_RL__r.Name, rw_Customer_Order__c, rw_Priority__c, Order_Date__c ' +
                    'FROM rw_Shipment__c ' +
                    'WHERE rw_Status__c = \'SAVED\' AND ' +
                    '(Warehouse_Status__c = \'Allocated\' ' +
                    'OR Warehouse_Status__c = \'Picking Slip Generated\' ' +
                    'OR Warehouse_Status__c = \'Packing Slip Generated\') ' +
                    'ORDER BY '+ sortorder + ' LIMIT 50';
            List<rw_Shipment__c> orderPriorityList = database.query(queryString);

            return orderPriorityList;
        } catch (Exception ex) {
            throw new AuraHandledException('No orders found found matching ' + ex.getMessage());
        }
  }
}

 
Best Answer chosen by Moshe Baitelman
Moshe BaitelmanMoshe Baitelman

I dove deeper on this. lightning:card needs to have the title attribute. Without it, it causes this error. 

Adding the title attribute solves this. If you are looking to use card for body styling only and do not want to display a title, you can do as Thuy suggests above.

All Answers

Thuy Pham 8Thuy Pham 8
Hi Moshe,

I ran into this exact problem too, and what solved it for me was eliminating the <lightning:card> tags. I was using it for styling purposes and was really interested in just using the body portion of the lightning:card. I replaced <lightning:card> with <div class="slds-media__body">, and Community Builder is working now and the component displays with the correct styling.

I referred to https://www.lightningdesignsystem.com/components/cards/ for the appropriate HTML and SLDS classes for styling.

Hope this helps you!
Moshe BaitelmanMoshe Baitelman

I dove deeper on this. lightning:card needs to have the title attribute. Without it, it causes this error. 

Adding the title attribute solves this. If you are looking to use card for body styling only and do not want to display a title, you can do as Thuy suggests above.

This was selected as the best answer