Icons with Notifications are used heavily in app development to provide navigation and context within the same screen. In this PCF article, I will provide a walkthrough on how you can implement a PCF control for both Canvas and Model that enable you to build a navigation bar with icons.
Demo
Control Logic
All code is made available at GitHub, so I will briefly walk you through the core components of the control.
Within your manifest file you should provide parameters for the various inputs that your control will be using. In this case we are going to be using a number of input parameters:
- Font-Awesome Class Name (fontAwesomeClassName)
This is a CSS library that contains hundreds of icon sets to use within your application. For examples see: https://fontawesome.com/v4.7.0/ - Font Size
This is the size of the font for the label. - Icon Size
This is the icon size in pixels - Font Color
This is the color used for both the icon and the label - Title
This is the title you wish to have under the icon - Notification Bubble Color
This is the color of the notification bubble that appears alongside an icon. - Notification Count
This is the count of the notifications to display along side each bubble.
Your manifest file should look something like this:
<?xml version="1.0" encoding="utf-8" ?>
<manifest>
<control namespace="AndrewLyControls" constructor="IconBuilder" version="0.0.1" display-name-key="IconBuilder" description-key="IconBuilder description" control-type="standard">
<!-- property node identifies a specific, configurable piece of data that the control expects from CDS -->
<property name="fontAwesomeClassName" display-name-key="Font Awesome Icon class name" description-key="e.g. fa fa-home, fa fa-search" of-type="SingleLine.Text" usage="bound" required="true" />
<property name="fontSize" display-name-key="Size" description-key="Default value is 12" of-type="Whole.None" usage="input" required="false"/>
<property name="iconSize" display-name-key="Icon" description-key="Default value is 40" of-type="Whole.None" usage="input" required="false"/>
<property name="fontColor" display-name-key="Color" description-key="Default value is #A7A7A7" of-type="SingleLine.Text" usage="input" required="false"/>
<property name="title" display-name-key="Title" description-key="Title description" of-type="SingleLine.Text" usage="input" required="false"/>
<property name="notiBubbleColor" display-name-key="Notification Bubble Color" description-key="Color of the notification bubble" of-type="SingleLine.Text" usage="input" required="false"/>
<property name="notiCount" display-name-key="Notification Count" description-key="Notification count" of-type="Whole.None" usage="input" required="false"/>
Next lets get started within your typescript file. Firstly we need to declare all the elements and variables to be used within your class.
import {IInputs, IOutputs} from "./generated/ManifestTypes";
export class IconBuilder implements ComponentFramework.StandardControl<IInputs, IOutputs> {
private _container: HTMLDivElement;
private _fa_classname: string;
private _fontsize: number;
private _iconsize: number;
private _fontcolor: string;
private _title: string;
private _notifycount: number;
private _notibubblecolor: string;
private i_div_element: HTMLDivElement;
private i_element: HTMLElement;
private label_element: HTMLLabelElement;
private noti_span_element: HTMLSpanElement;
Next we move onto the Init method. That creates the HTML elements and extracts the manifest inputs and assigns them to the variables for use within our init.
public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container:HTMLDivElement)
{
// Add control initialization code
this._container = document.createElement("div");
this.i_div_element = document.createElement("div");
this.i_element = document.createElement("i");
this.label_element = document.createElement("label");
this.noti_span_element = document.createElement("span");
// retrieve manifest inputs
this._fa_classname = context.parameters.fontAwesomeClassName.formatted ? context.parameters.fontAwesomeClassName.formatted : "fa fa-home";
this._iconsize = context.parameters.iconSize.raw ? context.parameters.iconSize.raw : 40;
this._fontsize = context.parameters.fontSize.raw ? context.parameters.fontSize.raw : 12;
this._fontcolor = context.parameters.fontColor.raw ? context.parameters.fontColor.raw : "#A7A7A7";
this._title = context.parameters.title.raw ? context.parameters.title.raw : "Sample";
this._notifycount = context.parameters.notiCount.raw ? context.parameters.notiCount.raw : 0;
this._notibubblecolor = context.parameters.notiBubbleColor.raw ? context.parameters.notiBubbleColor.raw : "green";
Next we set the attributes for each of our HTML elements and append them to our container.
// set span (notification)
this.noti_span_element.innerHTML = this._notifycount.toString();
if (this._notifycount > 0){
this.noti_span_element.setAttribute("style", "position:absolute;background-color:"+this._notibubblecolor+";padding: 2px 5px 2px 6px;color: white;font-size: 0.65em;border-radius: 50%;box-shadow: 1px 1px 1px gray;display:inline;")
}else{
this.noti_span_element.setAttribute("style", "position:absolute;background-color:"+this._notibubblecolor+";padding: 2px 5px 2px 6px;color: white;font-size: 0.65em;border-radius: 50%;box-shadow: 1px 1px 1px gray;display:none;")
}
this.i_div_element.appendChild(this.noti_span_element)
// set i element (icon)
this.i_element.setAttribute("class", this._fa_classname);
this.i_element.setAttribute("style", "font-size: " + this._iconsize + "px; color: " + this._fontcolor);
this.i_div_element.appendChild(this.i_element);
this._container.appendChild(this.i_div_element);
// set a element (title)
this.label_element.innerHTML = this._title;
this.label_element.setAttribute("style", "text-align: center; font-size: " + this._fontsize + "px; color: " + this._fontcolor);
this._container.appendChild(this.label_element);
container.appendChild(this._container);
And now we include the reference Style Sheet so that it knows which icon library to target. In our case it is font-awesome 4.7.0.
// Add the FontAwesome Stylesheet
var link = document.createElement("link");
link.id = "FontAwesomeURL";
link.rel = "stylesheet";
link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css';
// Add the request on the head of the document
document.getElementsByTagName("head")[0].appendChild(link);
Final piece of code before you can build your PCF component is to include actions upon update of your variables. We include this code within the updateView method that is created within our PCF skeleton class.
public updateView(context: ComponentFramework.Context<IInputs>): void
{
// Add code to update control view
this._fa_classname = context.parameters.fontAwesomeClassName.formatted ? context.parameters.fontAwesomeClassName.formatted : "fa fa-home";
this._iconsize = context.parameters.iconSize.raw ? context.parameters.iconSize.raw : 40;
this._fontsize = context.parameters.fontSize.raw ? context.parameters.fontSize.raw : 12;
this._fontcolor = context.parameters.fontColor.raw ? context.parameters.fontColor.raw : "#A7A7A7";
this._title = context.parameters.title.raw ? context.parameters.title.raw : "Sample";
this._notifycount = context.parameters.notiCount.raw ? context.parameters.notiCount.raw : 0;
this._notibubblecolor = context.parameters.notiBubbleColor.raw ? context.parameters.notiBubbleColor.raw : "green";
// val is the default when debugging
this.i_element.setAttribute("class", this._fa_classname);
this.i_element.setAttribute("style", "font-size: " + this._iconsize + "px; color: " + this._fontcolor);
this.label_element.innerHTML = this._title;
this.label_element.setAttribute("style", "text-align: center; font-size: " + this._fontsize + "px; color: " + this._fontcolor);
// set notification bubble
this.noti_span_element.innerHTML = this._notifycount.toString();
if (this._notifycount > 0){
this.noti_span_element.setAttribute("style", "position:absolute;background-color:"+this._notibubblecolor+";padding: 2px 5px 2px 6px;color: white;font-size: 0.65em;border-radius: 50%;box-shadow: 1px 1px 1px gray;display:inline;")
}else{
this.noti_span_element.setAttribute("style", "position:absolute;background-color:"+this._notibubblecolor+";padding: 2px 5px 2px 6px;color: white;font-size: 0.65em;border-radius: 50%;box-shadow: 1px 1px 1px gray;display:none;")
}
}
That’s it! Now you’re done, you can build your project and add to your canvas app.
Usage
Usage of the PCF control is straightforward,
- Add your PCF Control via the Custom > Code section as shown above.
- Add the IconBuilder PCF from the Insert menu
- Configure the parameters of your control.
(Note make sure you are using Font Awesome Version 4.7 for your icons, it doe not currently support version 5)
Hope you’ve enjoyed this short tutorial.
Source
You can find the source code and solution file for this PCF Component on my GitHub here:
https://github.com/365lyf/PCFControls/tree/master/IconBuilder