Change CTA Icon conditionally (based on CTA label)

Hi team,

For FAQ CTAs, I’m trying to change the icon that display on the buttons conditionally based on the contents of their corresponding CTA labels.

Example:

  • if my label contains a substring “read”, then I want a magnifying_glass icon.
  • if my lab contains a substring “call”, then I want a phone icon.

I think I’m running into an issue where, because some of my FAQ entities do not have CTAs filled out, the code breaks because the iconName is passed an empty string based for FAQ entities with no CTA values based on the conditional statements in my code below (also attaching a screenshot in case the code is illegible here).

  dataForRender(profile) {
var cta1 = ''
var cta2 = ''
if (profile.c_primaryCTA.label.includes("Read") == true) {
  cta1 = 'receipt'; // The icon to use for the CTA
}
else if (profile.c_primaryCTA.label.includes("Call") == true){
  cta1 = 'phone';
}

if (profile.c_secondaryCTA.label.includes("Read") == true) {
  cta2 = 'magnifying_glass'; // The icon to use for the CTA
}
else if (profile.c_secondaryCTA.label.includes("Call") == true){
  cta2 = 'person';
}


return {
  title: profile.name, // The header text of the card
  // subtitle: '', // The sub-header text of the card
  details: profile.answer ? ANSWERS.formatRichText(profile.answer, "answer", "_top") : null, // The text in the body of the card
  // If the card's details are longer than a certain character count, you can truncate the
  // text. A toggle will be supplied that can show or hide the truncated text.
  // showMoreDetails: {
  //   showMoreLimit: null, // Character count limit
  //   showMoreText: '', // Label when toggle will show truncated text
  //   showLessText: '' // Label when toggle will hide truncated text
  // },
  isExpanded: false, // Whether the accordion is expanded on page load
  // The primary CTA of the card
  CTA1: {
    label: profile.c_primaryCTA ? profile.c_primaryCTA.label : null, // The CTA's label
    iconName: cta1, // The icon to use for the CTA
    url: Formatter.generateCTAFieldTypeLink(profile.c_primaryCTA), // The URL a user will be directed to when clicking
    target: '_top', // Where the new URL will be opened. To open in a new tab use '_blank'
    eventType: 'CTA_CLICK', // Type of Analytics event fired when clicking the CTA
    // Event options for the analytics event fired when this CTA is clicked.
    eventOptions: this.addDefaultEventOptions({ /* Add additional options here */ }),
    // ariaLabel: profile.c_primaryCTA, // Accessible text providing a descriptive label for the CTA
  },
  // The secondary CTA of the card
  CTA2: {
    label: profile.c_secondaryCTA ? profile.c_secondaryCTA.label : null,
    iconName: cta2, // The icon to use for the CTA
    url: Formatter.generateCTAFieldTypeLink(profile.c_secondaryCTA),
    target: '_top',
    eventType: 'CTA_CLICK',
    eventOptions: this.addDefaultEventOptions({ /* Add additional options here */ }),
    // ariaLabel: profile.c_secondaryCTA,
  },
};

Best,
Luc

Note: I have the CTA icons updated to receipt and person in my code for testing purposes. For the conditions we want to see, the receipt and person icons should be displaying for CTAs.

Just realized I probably have to be using the ? logic. Regardless, still running into issues… seeing one console typerror issue of the following: Cannot read property ‘label’ of undefined.

return {
title: profile.name, // The header text of the card
// subtitle: ‘’, // The sub-header text of the card
details: profile.answer ? ANSWERS.formatRichText(profile.answer, “answer”, “_top”) : null, // The text in the body of the card
// If the card’s details are longer than a certain character count, you can truncate the
// text. A toggle will be supplied that can show or hide the truncated text.
// showMoreDetails: {
// showMoreLimit: null, // Character count limit
// showMoreText: ‘’, // Label when toggle will show truncated text
// showLessText: ‘’ // Label when toggle will hide truncated text
// },
isExpanded: false, // Whether the accordion is expanded on page load
// The primary CTA of the card
CTA1: {
label: profile.c_primaryCTA ? profile.c_primaryCTA.label : null, // The CTA’s label
iconName: profile.c_primaryCTA ? cta1icon : null, // The icon to use for the CTA
url: Formatter.generateCTAFieldTypeLink(profile.c_primaryCTA), // The URL a user will be directed to when clicking
target: ‘_top’, // Where the new URL will be opened. To open in a new tab use ‘_blank’
eventType: ‘CTA_CLICK’, // Type of Analytics event fired when clicking the CTA
// Event options for the analytics event fired when this CTA is clicked.
eventOptions: this.addDefaultEventOptions({ /* Add additional options here / }),
// ariaLabel: ‘’, // Accessible text providing a descriptive label for the CTA
},
// The secondary CTA of the card
CTA2: {
label: profile.c_secondaryCTA ? profile.c_secondaryCTA.label : null,
iconName: profile.c_secondaryCTA ? cta2icon : null, // The icon to use for the CTA
url: Formatter.generateCTAFieldTypeLink(profile.c_secondaryCTA),
target: ‘_top’,
eventType: ‘CTA_CLICK’,
eventOptions: this.addDefaultEventOptions({ /
Add additional options here */ }),
// ariaLabel: ‘’,
},
};
}

Hi Luc,

For any complicated conditional formatting like this, I’d recommend adding it as a Formatter so that you can reuse these functions easily.

1. Fork your Formatters.js File
Go to Jambo Commands > Override Theme. Select the formatters.js file.


Once you fork the file, you’ll see it in your static > js folder.
image

2. Add a function to determine the icon based on CTA Label
Below the last formatter in this file, add the below code.

  // Set icon based off of label
  static setIcon(cta) { 
    if (cta && cta.label) {
      if (cta.label.includes("Call")) {
        return "phone";
      }
      if (cta.label.includes("Read")) {
        return "receipt";
      }
    }
    return null;
  }

This accepts a CTA field - if the field is populated AND the label subfield is populated, the subsequent if statements will be triggered. Here you can use the includes function to return the corresponding icon name based off the label.

If none of these conditions are met, we return null.

3. Use this formatter in your faq-accordion forked card.
Update the icon of your CTAs to use this new formatter, passing the corresponding CTA field to the formatter function you’ve just created.

CTA1: {
        label: profile.c_primaryCTA ? profile.c_primaryCTA.label : null, // The CTA's label
        iconName: Formatter.setIcon(profile.c_primaryCTA), // The icon to use for the CTA
        url: Formatter.generateCTAFieldTypeLink(profile.c_primaryCTA), // The URL a user will be directed to when clicking
        target: '_top', // Where the new URL will be opened. To open in a new tab use '_blank'
        eventType: 'CTA_CLICK', // Type of Analytics event fired when clicking the CTA
        // Event options for the analytics event fired when this CTA is clicked.
        eventOptions: this.addDefaultEventOptions({ /* Add additional options here */ }),
        // ariaLabel: '', // Accessible text providing a descriptive label for the CTA
      },
      // The secondary CTA of the card
      CTA2: {
        label: profile.c_secondaryCTA ? profile.c_secondaryCTA.label : null,
        iconName: Formatter.setIcon(profile.c_secondaryCTA), // The icon to use for the CTA
        url: Formatter.generateCTAFieldTypeLink(profile.c_secondaryCTA),
        target: '_top',
        eventType: 'CTA_CLICK',
        eventOptions: this.addDefaultEventOptions({ /* Add additional options here */ }),
        // ariaLabel: '',
      },

The end result will automatically pick the icon based off of the label! Just add additional if statements if you want to add new conditions.

Hope this helps!

5 Likes

This is perfect… thank you Amani!!! :grinning:

Luc, this is such a cool idea!

1 Like

Hi @afarooque,

I noticed for a different client, when forking the formatters theme, the code now looks like we simply import defined formatters from somewhere else (refer to my screenshot below). How can I define this CTA method within this file?

This was covered in office hours. I’m all set!
For anyone wondering, for v1.6 onwards, you have to define it in formatters-internal.js and import it into formatters.js. (Fork both formatters-internal and formatters)

image image