2

I just added autosuggestion/autocomplete function in my bot-framework web chat(v-4) using react.js. But there are some issues i need to fix;

1.) While getting the suggestions i want to make the words which i type into the webchat to be Bold in the resulting suggestion list. I did that but the problem i'm facing now is that its only making the first letter as bold(as you can see in the image) i want to make it bold even if its inside a sentance.

2.) When i select an option from the suggestion list it has to be closed. It closes the other options but the selected option is not.(as shown in the image). I want to close that too.

3.) I want to make my up/down arrow for selecting options from the suggestion list.

Please find the images in below links,

17
  • Good job on this so far. It looks like you have three questions here. I want to make sure I understand question 1 first. You say "i want to make it bold even if its inside a sentance." In your screenshot you've typed t and the letter "t" is bold in each suggestion only as the first letter of the suggestion. Can you explain what letters you want bold in "Smartphone/Tablet Troubleshooting"? Do you just want the first t to be bold (at the end of Smart) or do you want every t to be bold? Also do you want it to be lowercase? For your second question you'll need to provide the "handle click" code. Commented Mar 5, 2020 at 1:35
  • Hi @KyleDelaney i want to make the firstly occuring letter bold. Means in Smartphone/Tablet Troubleshooting 't' is first occured in smar't', which should be bold. And for the 2nd question please find the handle click code attached above. Commented Mar 5, 2020 at 5:23
  • Thanks for the code, but this isn't what we need. Your second question says that when you click an option, the other options disappear but the one you clicked remains. I was thinking there was some code in the click handler that was making the options disappear incorrectly, but now I'm thinking that you don't have any code to make any options disappear and what's happening is that when you set the send box it triggers the same code to make options appear as when you type on the keyboard, but now that you've inputted a long phrase there's only one matching suggestion. Commented Mar 5, 2020 at 18:34
  • Since you'll want to reset the auto-suggestions component back to the invisible state that it was in originally, we'll need to see the code that makes it appear originally. Can you post that? Commented Mar 5, 2020 at 18:36
  • 1
    @KyleDelaney Ok. please find the attached css above. Commented Mar 18, 2020 at 5:46

1 Answer 1

1

For your first question, there may be two ways to do this. To do it the React way, you could use indexOf to find the index of the user text in the suggestion and then split the text into multiple React elements with one of them being bolded. If you want to use replace like you're currently doing then this may be a good opportunity to use dangerouslySetInnerHTML:

<div className="SuggestionParent" id="Suggestion1">
  {this.state.suggestions.map(suggestion => (
    <div className="Suggestion" onClick={this.handleSuggestionClick} >
      <div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} />
    </div>
  ))}
</div>

The "dangerous" warning is because you need to make sure you don't allow the user to provide any of the potential values that can go in the inner HTML or else they could inject script tags. As long as your suggestions are being drawn from a fixed database and the data is secure then you might be okay. Otherwise you would have to sanitize the HTML and in that case it would probably be easier to just not use dangerouslySetInnerHTML at all. If we do set the inner HTML, then we can use replace to just directly apply HTML tags to the string:

getSuggestionHtml(suggestion) {
  const lowerCaseSuggestion = suggestion.toLowerCase();
  return {
    __html: lowerCaseSuggestion.includes(this.state.suggestionTypedText) ? lowerCaseSuggestion
      .replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) : lowerCaseSuggestion
  };
}

For your second question, you said you've already solved it. I can see that you're using a Boolean switch to temporarily turn off the way you respond to the WEB_CHAT/SET_SEND_BOX action.

For your third question, there are a lot of design considerations that you have to ask yourself about when figuring out how your UI is going to work, like "What happens if the user mouses over the suggestions while they're using the arrow keys?" and "Should the highlighted suggestion be previewed in the send box before the user presses enter?" I was hoping to find a preexisting React autocomplete component that you could use instead of building your own because that would already address all these potential pitfalls. Unfortunately, the two prominent React autocomplete packages (here and here) both have the same two problems:

  1. They're not currently being maintained
  2. The targeted input is included in the component so you don't get to connect the component to a preexisting input.

However, they are both open source so we can model our own autocomplete functionality after them. I'll guide you through the basic functionality and you can expand on that as you please.

Keyboard events are generally handled in React using the onKeyDown property. I've placed it on an element that contains both Web Chat and your suggestions parent:

<div className={ROOT_CSS} onKeyDown={this.handleKeyDown.bind(this)}>
  <div className={WEB_CHAT_CSS + ''}>
    <ReactWebChat

That will handle all key presses, so you'll need a way to route to the function for the correct key. You could use a switch statement but the source code for react-autocomplete uses a lookup object and I think that's smart.

keyDownHandlers = {
  ArrowDown(event) {
    this.moveHighlight(event, 1);
  },
  ArrowUp(event) {
    this.moveHighlight(event, -1);
  },
  Enter(event) {
    const {suggestions} = this.state;
    if (!suggestions.length) {
      // menu is closed so there is no selection to accept -> do nothing
      return
    }
    event.preventDefault()
    this.applySuggestion(suggestions[this.state.highlightedIndex]);
  },
}

handleKeyDown(event) {
  if (this.keyDownHandlers[event.key])
  this.keyDownHandlers[event.key].call(this, event)
}

I've centralized the functionality for the up and down arrows into one function: moveHighlight. You will need to define a new property in your state to keep track of which suggestion has been selected by the keyboard. I'm keeping the name highlightedIndex from react-autocomplete.

moveHighlight(event, direction) {
  event.preventDefault();
  const { highlightedIndex, suggestions } = this.state;
  if (!suggestions.length) return;
  let newIndex = (highlightedIndex + direction + suggestions.length) % suggestions.length;
  if (newIndex !== highlightedIndex) {
    this.setState({
      highlightedIndex: newIndex,
    });
  }
}

For the enter key to apply a suggestion, you'll want to centralize your functionality so that it works the same way as a mouse click.

async handleSuggestionClick(event) {
  await this.applySuggestion(event.currentTarget.textContent);
}

async applySuggestion(newValue) {
  await this.setState({ typingChecking: "false", suggestions: [], highlightedIndex: 0 });
  this.state.suggestionCallback.dispatch({
    type: 'WEB_CHAT/SET_SEND_BOX',
    payload: {
      text: newValue,
    }
  });
  await this.setState({ typingChecking: "true" });
}

Finally, make sure the highlightedIndex property is used to render the highlighted index differently.

getSuggestionCss(index) {
  return index === this.state.highlightedIndex ? HIGHLIGHTED_CSS : SUGGESTION_CSS;
}

. . .

<div className="SuggestionParent" id="Suggestion1">
  {this.state.suggestions.map((suggestion, index) => (
    <div className={this.getSuggestionCss(index)} key={index} onClick={this.handleSuggestionClick} >
      <div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} />
    </div>
  ))}
</div>
Sign up to request clarification or add additional context in comments.

15 Comments

Hi, is there any way to change the styleset of adaptive cards. I want to change the button placement and title color. But i'm unable to do so with css. As the adaptive cards are using a common 'p' for all text blocks, so if i change the title color every text block color will be changed. How can i solve this?
So how can I do that using Hostconfig. As I'm calling my botframework webchat to the react front end, I dont know where should i write the code for this. Can you please help me by explaining what to do.
Hi Kyle, the app is showing the below error whenever i try to send a msg via the application. And there is no problem if i select the message from suggeston list. What is the reason for this problem? Please help Unhandled Rejection (Error): Given action "WEB_CHAT/SET_SEND_BOX", reducer "sendBoxValue" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.
Just use a different action instead of WEB_CHAT/SET_SEND_BOX. I put a console.log in my Redux middleware to see when each action gets executed. You can see the actions that fire when you send a message and then send one of those actions yourself, like DIRECT_LINE/POST_ACTIVITY perhaps. You can see the available actions here: github.com/microsoft/BotFramework-WebChat/tree/master/packages/…
Ok. so you mean i should use another action for that. Can i use the action with handleSuggestionClick to send the message by clicking it. What about sendMessage action?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.