Why ngx-microsoftbot-framework? | Table of Contents | Installation | Advanced Installation
This Angular library achieves 3 goals
-
Easy setup to render a Web Chat bot in your Angular application including providing the secret webchat key for the bot application. You can use a web call for a temporary token or directly use your secret key.
-
It allows you to add 2 styling guidelines for your microsoft chat bots
2a. The Recommended styling model from Microsoft is the "Branding Webchat Styling." This is achieved via styleSetOptions. This has limited style set options that adhere to a predefined property set of mutable styles. More information can be found here: Branding WebChat Styling.
2b. The Other alternative to styling the chat bot is the "Idiosyncratic Manual Styling." This is acheived via createStyleSet. This has full access to the webchat dependency for styling specific property methods. More information can be found here: Idiosyncratic Manual Styling.
-
Provide flexability of using either the WebChat library directly via the
BotHelperDirective.renderWebChat()
method in an app component or by using the provided feature set of thebotDirective()
to initiate the webchat bot. Either method uses theBotService
to pass the secret key either directly in the app or through the bot-framework api to recieve and use a temporary token which is recommended.
You can add a one or both objects to achieve your styling goals. From my testing you may have to use both styles because the base properties are not the same across methods. Text color is achieved in styleSetOptions but not used in createStyleSet. So while createStyleSet allows you to use custom objects i.e. root you will need the other payload to achieve text styling. Hopefully, Microsoft works this out in future updates.
If you want complete custom styling to a granular level then I would use both payloads with that exact same base options along with the createStyleSet payload of custom styling objects. I will give specific examples below. Make sure to read the bot documentation for a full understanding of each styling pattern.
- Before We Begin
- Installation
- Advanced Installation
- Bot Demo
- API
- Compatibility
- Troubleshooting
- Contributing
First, read over the documentation about the Bot Framework Web Chat api.
This repository contains code for the Bot Framework Web Chat component. The Bot Framework Web Chat component is a highly-customizable web-based client for the Bot Framework V4 SDK. The Bot Framework SDK v4 enables developers to model conversation and build sophisticated bot applications.
Warning The information can be a lot to take in at first. And the npm install botframework-webchat referred to in the documentation is specifically built for React. Hence, why I built this repo specifically for Angular.
The good news is the core of the Web Chat api is on a URL called Web Chat CDN
Next, Well you're going to need a bot! So where do we get one of these awesome bots? Create and learn about the Microsoft Bot Framework over at the Azure Bot Service. Here you can create a bot and obtain a secret key for the Web Chat setup.
To be clear, we will be implementing the cdn inside of the Angular applications index.html file. The URL gives the latest Web Chat library.
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
ngx-microsoft-botframework does not contain any core build files. It uses the directline api which among many things renders the Web Chat client. My main objective is to allow you to use the api fully
Install ngx-microsoft-bot-framework
via npm
:
npm i ngx-microsoft-bot-framework --save
Use the Angular-Cli ng add command to update the Angular project:
ng add ngx-microsoft-bot-framework
Add module to NgModule imports:
<!--- app.component.module -->
import { NgxMicrosoftBotFrameworkModule } from 'ngx-microsoft-bot-framework';
@NgModule({
...
imports: [NgxMicrosoftBotFrameworkModule, ...]
...
})
Import all of these interfaces, classes and life-cycle hooks into the component bot will render:
<!--- app.component.ts -->
import { Component, ElementRef, OnInit, AfterViewInit, ViewChild } from "@angular/core";
Import the ngx-microsoft-bot-framework
module and it's directives, services and interfaces:
Note: Depending on your webchat implementation you may only wish to use the BotDirective
or the BotHelperDirective
import { BotDirective, BotHelperDirective, StyleSetDirective, BotService, ComService, IPayload, DEFAULT_OPTIONS } from 'ngx-microsoft-bot-framework';
Add these 2 properties
@ViewChild("botWindow", { static: false }) botWindowElement: ElementRef;
passViewChild: ViewChild;
Add the default Payload
property:
The false setting for secretSetting
disables the web call to the botframework/api/token generator so the url is not neccessary:
Note: The url is optional if the secretSetting
is set to false | userId
and webSocket
are optional settings
payload: IPayload = {
secret: 'VQDSUGBn3Lo.SxWHKP4UXAvJWZaLXkUQGBABH4sjZU3NIjeesJnmW-g',
url: 'https://webchat.botframework.com/api/tokens',
secretSetting: true,
userId: 'USER_ID',
webSocket: true
};
Optional: Styling the bot with 1 or 2 payloads is optional
Add the styleSetOptions
and or createStyleSet
payload properties:
stylesetPayload: DEFAULT_OPTIONS = {
rootHeight: '100%',
botAvatarInitials: 'BF',
userAvatarInitials: 'CH',
backgroundColor: '#131313',
...
root: {
/* width */
' ::-webkit-scrollbar': {
width: '3px'
},
...
},
text_content: {
fontFamily: '\'Comic Sans MS\', \'Arial\', sans-serif',
fontWeight: 'bold',
...
}
};
styleOptionsPayload: DEFAULT_OPTIONS = {
rootHeight: '100%',
botAvatarInitials: 'BF',
userAvatarInitials: 'CH',
backgroundColor: 'red',
...
};
Add the communicatoin services and bot directive to the constructor:
constructor(
private comService: ComService,
private bot: BotDirective
) { }
Add the methods that will be called into the ngOnInit()
and ngAfterViewInit()
life-cylce hooks:
setBotDirective(): void {
this.passViewChild = this.botWindowElement.nativeElement;
this.bot.botDirective(this.passViewChild);
}
obtainLocalToken() {
this.comService.obtainToken(this.payload);
}
obtainStylePayload() {
this.comService.obtainStylePayload(this.stylesetPayload, this.styleOptionsPayload)
}
Call the methods in the 2 life-cycle hooks. ngAfterViewInit()
is used because of the Angular 8/9 ViewChild
documentation stating ViewChild without a template *ngIf
statement should be set to {static: false}
and be called in the ngAfterViewInit()
hook:
public ngOnInit(): void {
this.obtainStylePayload();
this.obtainLocalToken();
}
public ngAfterViewInit(): void {
this.setBotDirective();
}
Add ViewChild template dom elements:
<!--- app.component.html -->
<div class="flex">
<div class="main-container">
<h1>Welcome to flight booker</h1>
<div class="webchat-container" #botWindow></div>
</div>
</div>
Add css styling to template to match with bot styling changes:
<!--- app.component.css -->
:host,
.flex,
.main-container,
.webchat-container {
height: 85%;
overflow: hidden;
color: white;
}
.flex {
display: flex;
height: 100%;
}
...
Lastly, include the Web Chat CDN to the index.html file:
<!--- index.html -->
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
That's It! You should be off and running at this point
I am aware that more options from the webchat api will need to have the option to passthrough through the payload such as userId and Name and other api properties. This will be added in a future release.
You, like all great developers, like to have full-controll of your library's capabilities. The previous use case can be for production and demo purposes but there may be other features/concerns such as connection status checks, postActivity, general api information, etc. that you would want full access to.
With the v1.1.0 update the BotHelperDirective
's primary function is the renderWebChat() method. This is overloaded with 4 signatures total. This allows you to take over direct control over the WebChat api's properties and methods.
The main reason for this is to gain access to the directLine api and all of the other WebChat
properties and methods. You can read more about all of the directLine api capabilities here https://github.com/microsoft/BotFramework-DirectLineJS. Later, I will illustrate how to install the npm DirectLineJS library to use the ConnectionStatus
class for granular bot activity returns such as FailedToConnect
.
If you followed the instructions above. In your app.component.ts file's ngAfterViewInit()
comment out the following:
<!--- app.component.ts -->
// this.setBotDirective();
Import botHelperDirective
and IWebChat
from the ngx-microsoft-bot-framework
library:
import { ..., BotHelperDirective, IWebChat, ... } from 'ngx-microsoft-bot-framework';
Add the BotHelperDirective
to the app component providor:
@Component({
...
providers: [BotService, ComService, BotDirective, BotHelperDirective, StyleSetDirective],
...
})
Add the renderObject
property :
renderObject: IWebChat;
Add BotHelperDirective
and BotService
to the constructor:
constructor(
private comService: ComService,
private bot: BotDirective,
private botHelper: BotHelperDirective,
private botService: BotService,
) { }
Copy this code into your app component below your ngOnInit
function:
customBotDirective(): void {
let token: string;
this.passViewChild = this.botWindowElement.nativeElement;
this.botService.getTokenObs()
.subscribe(
response => {
this.payload.secretSetting ? token = response.body : token = this.payload.secret;
if (response.status == 200 && response.statusText == 'OK' || response == false) {
const directLine = window.WebChat.createDirectLine({
secret: token,
webSocket: true
});
const styleSet = window.WebChat.createStyleSet(this.stylesetPayload);
let userId = 'USER_ID';
this.renderObject = {
directLine: directLine,
userID: 'USER_ID',
styleOptions: this.styleOptionsPayload,
styleSet: styleSet,
disabled: false
}
// this.bot.renderWebChat(this.passViewChild, null, directLine, userId, this.styleOptionsPayload, styleSet);
this.botHelper.renderWebChat(this.passViewChild, this.renderObject);
directLine
.postActivity({
from: { id: "USER_ID", name: "USER_NAME" },
name: "requestWelcomeDialog",
type: "event",
value: "token"
})
.subscribe(
id => console.log(`Posted activity, assirgned ID ${id}`),
error => console.log(`Error posting activity ${error}`)
);
styleSet.textContent = Object.assign(
{},
styleSet.textContent,
{
cursor: 'crosshair',
color: 'white'
}
);
styleSet.root = Object.assign(
{},
styleSet.root,
{
... css here
}
);
}
});
}
Let's break apart the above code to understand what is going on here
- Use the
botService
to generate your payload's token settings - Initiate the
WebChat.createDirectLine
api
this.botService.getTokenObs()
.subscribe(
response => {
this.payload.secretSetting ? token = response.body : token = this.payload.secret;
if (response.status == 200 && response.statusText == 'OK' || response == false) {
const directLine = window.WebChat.createDirectLine({
secret: token,
webSocket: true
});
- Use the
botHelper
'srenderWebChat()
to intiate theWebChat
api properties. Below is an example object,renderObject
of api properties that can be set.
Note: You can choose to render the object to pass through or use individual settings in the method overload to intitate the renderWebChat()
method. Either provide settings and not the renderObject i.e. null
or the this.passViewChild
and this.renderObject
property and object
A short list of the WebChat
can be found here: Api Properties
let userId = 'USER_ID';
this.renderObject = {
directLine: directLine,
userID: 'USER_ID',
styleOptions: this.styleOptionsPayload,
styleSet: styleSet,
disabled: false
}
// this.bot.renderWebChat(this.passViewChild, null, directLine, userId, this.styleOptionsPayload, styleSet);
this.botHelper.renderWebChat(this.passViewChild, this.renderObject);
- Use
directLine.postActivity()
to initiate the bot i.e. a welcome adaptive card that begins when the bot is loaded
directLine
.postActivity({
from: { id: "USER_ID", name: "USER_NAME" },
name: "requestWelcomeDialog",
type: "event",
value: "token"
})
.subscribe(
id => console.log(`Posted activity, assirgned ID ${id}`),
error => console.log(`Error posting activity ${error}`)
);
- If using idiosyncratic styling, mentioned previously, initiate the
WebChat.createStyleSet()
method and pass through thestylesetPayload
object previously create for your styling options
const styleSet = window.WebChat.createStyleSet(this.stylesetPayload);
- Next, if you want to further customize styling the
styleSet
property here is an example of a customized styling option
styleSet.textContent = Object.assign(
{},
styleSet.textContent,
{
cursor: 'crosshair',
color: 'white'
}
);
- Lastly, initiate the function in
ngAfterViewInit()
this.customBotDirective();
- Bonus! If you want complete granular control of the
DirectLine
class and other classes such asConnectionStatus
import in theBotFramework-DirectLineJS
library documented here after installing the npm package
npm i botframework-directlinejs
import { DirectLine, ConnectionStatus } from 'botframework-directlinejs';
Example usage:
directLine.connectionStatus$
.subscribe(connectionStatus => {
let msg: string;
switch(connectionStatus) {
case ConnectionStatus.Uninitialized: // the status when the DirectLine object is first created/constructed
msg = 'uninitialized'
case ConnectionStatus.Connecting: // currently trying to connect to the conversation
msg = 'connecting'
case ConnectionStatus.Online: // successfully connected to the converstaion. Connection is healthy so far as we know.
msg = 'online'
case ConnectionStatus.ExpiredToken: // last operation errored out with an expired token. Your app should supply a new one.
case ConnectionStatus.FailedToConnect: // the initial attempt to connect to the conversation failed. No recovery possible.
msg = 'FAILED'
case ConnectionStatus.Ended: // the bot ended the conversation
}
console.log('msg = ', msg)
});
The demo is live bot on the repository's github.io
page here: https://xtianus79.github.io/ngx-microsoft-bot-framework
Below is a short list of api properties if you choose to pass through the renderObject
in the bot.renderWebChat()
method. A full list can be found here: https://github.com/microsoft/BotFramework-WebChat#web-chat-api-reference
Property | Description |
---|---|
activityMiddleware | A chain of middleware, modeled after Redux middleware, that allows the developer to add new DOM components on the currently existing DOM of Activities. The middleware signature is the following: options => next => card => children => next(card)(children). |
attachmentRenderer | The "flattened" version of attachmentMiddleware. |
createDirectLine | A factory method for instantiating the Direct Line object. Azure Government users should use createDirectLine({ domain: 'https://directline.botframework.azure.us/v3/directline', token }) ; to change the endpoint. The full list of parameters are: conversationId, domain, fetch, pollingInterval, secret, streamUrl, token, watermark webSocket. |
disabled | Disable the UI (i.e. for presentation mode) of Web Chat. |
directLine | Specify the DirectLine object with DirectLine token. We strongly recommend using the token API for authentication instead of providing the app with your secret. To learn more about why, see the authentication documentation or connecting client app to bot |
styleOptions | Object that stores customization values for your styling of Web Chat. For the complete list of (frequently updated) default style options, please see the defaultStyleOptions.js file. |
styleSet | The non-recommended way of overriding styles. |
Comaptible as of Angular 8 ivy with botframework-webchat 4.5.1 for ngx-microsoft-bot-framework
1.0.0 - 1.1.0
Report issues for help
Help is always welcome! This library will follow it's compatibility with official release from the official botframework-webchat api. Contributions include not only pull requests but feature additions/recommendations and feedback for improving the library.