11

Is there a way to get an SObject (Tab) icon (name) to be referenced from the design system resource?

I'm building a custom visualforce page that will be displayed using Lightning, so I need to style it accordingly. My problem is that I really don't know what is the best practice to get the icon or at least it's name so I can reference the design system resource, here is an example:

I have a visualforce page with an icon as:

<span class="slds-icon_container slds-icon_container--circle slds-icon-action-description">
    <svg aria-hidden="true" class="slds-icon slds-icon--small">
        <use xlink:href="{!URLFOR($Resource.SLDS100,'assets/icons/custom-sprite/svg/symbols.svg#custom44')}"></use>
   </svg>
</span>

And I need to do something like this:

<span class="slds-icon_container slds-icon_container--circle slds-icon-action-description">
    <svg aria-hidden="true" class="slds-icon slds-icon--small">
        <use xlink:href="{!URLFOR($Resource.SLDS100,iconName)}"></use>
   </svg>
</span>

Where iconName is the URL of the svg icon of the current standardController object, right now I'm getting it from the extension like (not exactly):

public String getIconName(){
    List<Schema.DescribeTabSetResult> tabSetDesc = Schema.describeTabs();
    List<Schema.DescribeTabResult> tabDesc = new List<Schema.DescribeTabResult>();
    List<Schema.DescribeIconResult> iconDesc = new List<Schema.DescribeIconResult>();

    for(Schema.DescribeTabSetResult tsr : tabSetDesc) {
        tabDesc.addAll(tsr.getTabs());
    }

    for(Schema.DescribeTabResult tr : tabDesc) {
        if (tr.getSobjectName() == 'Custom__c') {
            iconDesc.addAll(tr.getIcons());
        }
    }

    String u;
    for (Schema.DescribeIconResult ir : iconDesc) {
        if (ir.getContentType() == 'image/svg+xml'){
            u = ir.getUrl();
            break;
        }
    }
    Integer s = u.indexOf('/custom/') + '/custom/'.length(),
            e = u.length() - 4;
    return 'assets/icons/custom-sprite/svg/symbols.svg#' + u.substring(s, e);
}

But with lightning in mind, it really looks like there should be a better way to achieve this (without all those loops), and this workaround doesn't work for a custom icon.

Notes:

  1. Similar question
  2. This needs to work in a managed package, where the icon changes from org to org.
2

For any of those who may be looking for an even more generic solution, or possibly a use case where you are simply using the SLDS styles in a VF page, I have a method which returns the lightning style class for the wrapper of the tab icon, in addition to its Lightning png icon to fill it. This is supported in a managed package, and will also pull custom icons that are defined by customers/packages installed. If an object is passed in that does not have a tab definition, it simply returns the SLDS Custom icon as a default. My use case required dynamic loading of the icon depending on a configuration for the object, so a dynamic IMG binding was much more realistic to switch up on the fly than repainting an SVG.

Method that takes in sObject Name and returns a map of properties (iconStyle, iconURL)

/***
 * Explores the schema of the soject passed in and finds lightning icon style and image url for sObject
 * If nothing is found, defaults to the custom icon
 *
 * @param   sObjectTypeName       the sObject to find the icon for
 * @return  Map<String,String>    Map of properties about the icon to be consumed by the front end.
 *                                Right now, returns values for keys: iconStyle,iconURL
 */
global static Map<String,String> retrieveIconForObject(String sObjectName) {    
    String iconStyle;
    String iconURL;
    String iconTag;
    Map<String.String>                iconPropertyMap = new Map<String.String>();
    List<Schema.DescribeTabSetResult> tabSetDesc      = Schema.describeTabs();
    List<Schema.DescribeTabResult>    tabDesc         = new List<Schema.DescribeTabResult>();
    List<Schema.DescribeIconResult>   iconDesc        = new List<Schema.DescribeIconResult>();

    for(Schema.DescribeTabSetResult tsr : tabSetDesc){
       tabDesc.addAll(tsr.getTabs()); 
    }
    for(Schema.DescribeTabResult tr : tabDesc) {
        if( sObjectName == tr.getSobjectName() ) {
            system.debug(tr.getIcons());
            if(!tr.getIcons().isEmpty()){
                iconDesc.addAll(tr.getIcons());
            }else{
                if( tr.isCustom() == true ) {
                    iconStyle = 'slds-icon-standard-custom';
                    iconURL   = '/img/icon/t4v35/standard/custom_120.png';
                } else {
                    iconStyle = 'slds-icon-standard-' + sObjectName.toLowerCase();
                    iconURL   = '/img/icon/t4v35/standard/' + sObjectName.toLowerCase() + '_120.png';
                }
            }
        }
    }
    for (Schema.DescribeIconResult ir : iconDesc) {
        if(ir.getTheme() =='custom' && !ir.getContentType().startsWith('image/svg')){//custom icon thats not an svg
            iconTag   = 'custom';
            iconURL   = ir.getURL();
            iconStyle = 'slds-icon-standard-custom';
            break;
        }else if(ir.getWidth() == 120 && ir.getTheme() =='theme4' && ir.getContentType() == 'image/png'){//large lightning icon image
            if(ir.getURL().contains('/custom/')){ //Icon is from the Custom Sprite
                iconTag    = ir.getURL().substringBetween('custom/','.png').substringBefore('_');
                iconURL    = '/img/icon/t4v35/custom/' + iconTag + '_120.png';
                iconStyle  = 'slds-icon-custom-'+ iconTag;
                break;
            }else if(ir.getURL().contains('/standard/')){//Icon is from the Standard Sprite
                iconTag    = ir.getURL().substringBetween('standard/','.png').substringBefore('_');
                iconURL    = '/img/icon/t4v35/standard/' + iconTag + '_120.png';
                iconStyle  = 'slds-icon-standard-'+ iconTag;
                break;
            }
        }
    }
    //if no icons are found, just default to the Custom lightning icon
    if(iconStyle == null){
        iconStyle = 'slds-icon-standard-custom';
        iconURL   = '/img/icon/t4v35/standard/custom_120.png';
        iconTag   = 'No Lightning Icon Found';
    }
    //return a map with our properties for the front end
    iconPropertyMap.put('iconStyle',iconStyle);
    iconPropertyMap.put('iconURL',  iconURL);

    return iconPropertyMap;
}

Example usage for binding:

<span data-bind="css: selectedMapObjectIconClass" class="slds-icon_container slds-avatar">
  <img data-bind="attr:{src: selectedMapObjectIconUrl}"></img>
</span>
2

I know it is very late, but below solution worked for me for Standard and custom object.

Apex Class

    @AuraEnabled
    public static String getIconName(String sObjectName){
        String u;
        List<Schema.DescribeTabSetResult> tabSetDesc = Schema.describeTabs();
        List<Schema.DescribeTabResult> tabDesc = new List<Schema.DescribeTabResult>();
        List<Schema.DescribeIconResult> iconDesc = new List<Schema.DescribeIconResult>();

        for(Schema.DescribeTabSetResult tsr : tabSetDesc) { tabDesc.addAll(tsr.getTabs()); }

        for(Schema.DescribeTabResult tr : tabDesc) {
            if( sObjectName == tr.getSobjectName() ) {
                if( tr.isCustom() == true ) {
                    iconDesc.addAll(tr.getIcons());
                } else {
                    u = 'standard:' + sObjectName.toLowerCase();
                }
            }
        }
        for (Schema.DescribeIconResult ir : iconDesc) {
            if (ir.getContentType() == 'image/svg+xml'){
                u = 'custom:' + ir.getUrl().substringBetween('custom/','.svg').substringBefore('_');
                break;
            }
        }
        return u;
    }

Lightning Component

<aura:component controller="yourApexController" implements="flexiPage:availableForAllPageTypes,force:hasSObjectName">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <aura:attribute name="sObjectName" type="String" />
    <aura:attribute name="iconName" type="String" />
    <lightning:icon iconName="{!v.iconName}" size="large" alternativeText="Indicates approval"/>
</aura:component>

Lightning JS controller

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getIconName");
        action.setParams({ "sObjectName" : component.get("v.sObjectName") });
        action.setCallback(this, function(response) {
           component.set("v.iconName", response.getReturnValue() );
        });
        $A.enqueueAction(action);
    }
})

Let me know if it works for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.