BotFramework-Webchat Middleware: defining custom CSS class names

My goal is to dynamically assign CSS class names based on the card type to the corresponding HTML element.

I've achieved this by utilizing the [AdaptiveCard.customCssSelector] 1 attribute. For example, you can simply include

builder.card.customCssSelector = "ac-thumbnail";
in this line and the resulting HTML block will have
class="ac-container ac-thumbnail"
.

However, I want to avoid relying on Botframework-Webchat updates and instead integrate this logic into a middleware. As per the BotFramework-Webchat documentation, it's feasible to add attachmentMiddleware to the renderWebChat function to manipulate HTML elements.
Although I'm able to retrieve activities and attachments, I face difficulty in altering HTML blocks or adding a CSS selector.

Below is my middleware code:

export const cardCssSelector = ({ dispatch }) => next => action => {
    if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
        const { activity } = action.payload;
         for (var index in activity.attachments) {       
            const card  = activity.attachments[index].content;
            if(card.tap && card.tap.value){
                card.customCssSelector = 'tap';
            }
        }
    }
    console.log(action);
    return next(action);
};

Unfortunately, this approach doesn't work as the attachments lack the customCssSelector attribute.

Answer №1

To achieve custom styling for web chat, some minor modifications are necessary. Here are a few key points to keep in mind:

  • It is essential to match the style to a value passed in the card rather than the activity. This helps identify specific cards in the HTML document that require styling. In this case, matching is based on the button text value for simplicity.
  • In Web Chat, cards are rendered as adaptive cards within the document.
  • The adaptiveCards [HTMLCollection] is converted into an array (cards) for easier iteration.
  • The addition of card- classes helps map the CSS styles to the corresponding cards.
  • Regardless of the type of adaptive card, buttons generally appear as the 3rd child (children[2]) in the document structure. Modifications may be needed for different card layouts.
  • For activities containing multiple cards, adjustments might be necessary, following a similar setup outlined below.

Start by creating a store and filtering incoming activities and messages based on the ac-adaptiveCard class.

const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => async action => {
  if(activity.type === 'message') {
    let aCards = document.body.getElementsByClassName('ac-adaptiveCard');
    let bCards = Object.values( aCards);

    for(let i = 0; i <= bCards.length - 1; i++) {
      if( cards[i].children[2] && cards[i].children[2].innerText && cards[ i ].children[ 2 ].innerText === 'Request Assistance') {
        cards[i].className += ' card-Adaptive'
      }

      if( cards[i].children[2] && cards[i].children[2].innerText && cards[ i ].children[ 2 ].innerText === 'Service details') {
        cards[i].className += ' card-Hero'
      }
    }
  }
}

Apply styling to the cards using assigned classes.

.card-Adaptive {
  background-color: black;
}

.card-Adaptive p {
  color: white;
}

.card-Hero {
  background-color: green;
}

Include the store parameter for rendering.

window.ReactDOM.render(
  <ReactWebChat
    directLine={ directLine }
    store={store}
  />,
  document.getElementById( 'webchat' )
);

An adaptive card appears in black while a hero card displays in green.

https://i.sstatic.net/ufF9H.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular D3 - The method 'getBoundingClientRect' is not present in the 'Window' type

Check out this StackBlitz demo I created: https://stackblitz.com/edit/ng-tootltip-ocdngb?file=src/app/bar-chart.ts In my Angular app, I have integrated a D3 chart. The bars on the chart display tooltips when hovered over. However, on smaller screens, th ...

Calculating Events with the onChange Method in Typescript

How do I calculate the total ticket price when I adjust the number of individuals? HTML Code : <div class="row"> <div class="col-md-6"> <label for="person">Person</label> <div class="form-group"> ...

Guidelines for crafting an intricate selector by utilizing mergeStyleSets and referencing a specific class

I'm currently in the process of developing a web application using ReactJS. In my project, I have the following code: const MyComponent = (props: { array: Array<Data> }) => { const styles = mergeStyleSets({ container: { ...

How to initiate a refresh in a React.js component?

I created a basic todo app using React, TypeScript, and Node. Below is the main component: import * as React from "react" import {forwardRef, useCallback, useEffect} from "react" import {ITodo} from "../types/type.todo" import ...

Ways to obtain the Map object from HTTPClient in Angular

When calling a REST endpoint, the return type is as follows: ResponseEntity<Map<String, List<Object>>> How can I handle this response on the Angular side? I attempted the following approach: let requiredData = new Map<String, Array&l ...

How does the keyof operator fetch non-enumerable inherited properties from an object literal type?

Take a look at this TypeScript code: 'use strict'; type Value = 1 | 2 ; type Owner = 'ownerA' | 'ownerB'; type ItemType = 'itemTypeA' | 'itemTypeB'; type Item = { type: ItemType; owner: Owner; value: ...

Stop allowing the entry of zero after a minus sign

One of the features on our platform allows users to input a number that will be automatically converted to have a negative sign. However, we want to ensure that users are unable to manually add a negative sign themselves. We need to find a solution to pre ...

Leveraging a React hook within a Next.js API route

I am looking for a way to expose the data fetched by a React.js hook as a REST endpoint using Next.js. To create a REST endpoint in Next.js, I can easily use the code below in pages/api/index.tsx export default function handler(req: NextApiRequest, res: N ...

Incorporate a stylish gradient background into react-chartjs-2

I am currently working on adding a gradient background with some transparency to a radar graph within a react component. So far, I have only found solutions that involve referencing a chartjs canvas in an html file, but none for implementing it directly in ...

Exploring the world of functional programming in Java can be a rewarding experience, especially

I am seeking a method to define generic computation on a data set and have the compiler alert me if there are any errors. Having experience with TypeScript, I have seen that you can achieve something like this: /** * Type inferred as: * Array<{ * ...

Step-by-step guide on importing Nano (CouchDB) using Typescript

I am facing difficulty in importing and using nano in my node application. According to the documentation, the JavaScript way is: var nano = require('nano')('http://localhost:5984'); How can I achieve this with TypeScript? I attempt ...

What is the process for setting up a node test launch configuration?

I have some "node 18 test runner" tests ready to be executed. I can run them using the following command: node --loader tsx --test tests/**/*.ts To debug these tests in vscode, I realized that I need to set up a configuration entry in my launch.json. But ...

Preventing the conversion of literals to classes in TypeScript

Using TypeScript, you can convert object literals to a class by doing the following: let businessObj = new ScenarioController(<FormatService>{ format: x => x }); Is there a way to prevent these types of casts in the compiler or linter? Oft ...

Accessing the value of a FormControl in HTML代码

Modifying the value of a form select element programmatically presents an issue. Even after changing the value in the form, the paragraph element "p" remains hidden. However, if you manually adjust the form's value, the visibility of the "p" element ...

Leverage TypeScript to enforce the value of a property based on the keys of another property

The issue at hand is illustrated in the following example: type ExampleType = { properties: { [x: string]: number; }; defaultProperty: string; }; const invalidExample: ExampleType = { properties: { foo: 123, }, defaultProperty: "n ...

Navbar Growth Effect

I'm attempting to create an expanding effect in my navbar using Angular. When I click on "show information," the content should slide up. The issue is that the top part of my footer does not follow the effect. I have tried something like: <foot ...

Exporting a class from an index.ts file may result in a problem where the injected constructor is

Utilizing an index.ts file to manage exports, following the guidelines outlined in the Angular 2 style guide (https://github.com/mgechev/angular2-style-guide/blob/master/old/README.md#directory-structure), has been successful throughout my application deve ...

Incorporate typings into your CDN integration

I'm interested in utilizing a CDN to access a JSON validation library, as it's expected to provide faster performance (due to retrieving the file from the nearest server within the CDN). The JSON validation library in question can be found here: ...

Angular 8: Issue with PatchValue in Conjunction with ChangeDetector and UpdateValue

I am puzzled by the fact that PatchValue does not seem to work properly with FormBuilder. While it shows data when retrieving the value, it fails to set it in the FormBuilder. Does anyone have an idea why this might be happening? I am utilizing UpdateValue ...

Invoking event emitter within a promise in Angular 2

My event emitter is not functioning properly within a promise's then method. No errors are being generated, it just won't execute. In the child component: @Output() isLoggingIn = new EventEmitter<boolean>(); onLogin() { this.isLoggingI ...