With TalkJS’s Conversation Actions, you can easily add custom options to your conversations. In this tutorial, we’ll demonstrate how to add a custom action that lets you change the title or image of a group chat. The action then sends a request to your backend server, which calls TalkJS’s REST API to update the conversation.

To follow along, you’ll need:

  • A TalkJS account. TalkJS provides a ready-to-use chat client for your application. Your account gives you access to TalkJS's free development environment.
  • An existing TalkJS project using the JavaScript Chat SDK. See our Getting Started guide for an example of how to set this up.
  • An installation of Node.js along with the npm package manager. We’ll use this to create our backend server.

Before going further, if your application uses a one-on-one chat you should tweak it a bit to change it to a group chat. This is because conversation images and titles are more relevant for a group chat rather than a one-on-one chat as the latter displays the image of the user. See this guide to learn how to set up a group chat.

We’ll build up the feature step by step in the following sections. If you would rather see the complete example code, see the GitHub repo for this tutorial.

Add a new action to the conversation

To trigger an action from the TalkJS chat UI, we need to add a custom action.You can configure which actions a user can take based on their role. In this case, we’ll add it to the “default” role.

Go to your TalkJS dashboard and navigate to the Roles tab. Select the “default” role and go down to the Custom conversation actions section. Add a new action and name it “editTitleOrImage” with the label “Edit title or image”. Don’t forget to click Save all roles to persist your changes.

The conversation action options in the TalkJS dashboard
The conversation action options in the TalkJS dashboard

The new action appears in our group chat as shown in the image below:

The new "Edit title or image" menu option
The new "Edit title or image" menu option

If you're using a legacy theme, or customized a theme before the custom conversation actions feature was released, you'll need to add this menu to your theme before it will show up. See our docs for details on how to edit the theme.

Adding a modal to accept the new image and title

After following the Getting Started guide, you should have a chat up and running. Since we’re adding an action to edit the existing title and image of a conversation, we need a way to get new values for these. To do this, we can add a modal that asks you to input these values. In your index.html file, right below the talkjs-container div, add the following code:

<div
  class="modal fade"
  id="editModal"
  tabindex="-1"
  role="dialog"
  aria-labelledby="editModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Edit Conversation Title/Image</h5>
        <button
          type="button"
          class="close"
          data-dismiss="modal"
          aria-label="Close"
        >
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <form onsubmit="getFormData(event)">
          <div class="form-group">
            <label for="conversationTitle"
              >Enter a new conversation title:</label
            >
            <input type="text" class="form-control" id="conversationTitle" />
          </div>
          <div class="form-group">
            <label for="imageURL">Enter a new image URL:</label>
            <input type="text" class="form-control" id="imageURL" />
          </div>
          <input type="submit" class="btn btn-primary" />
        </form>
      </div>
    </div>
  </div>
</div>

This adds a modal with two input fields, one for the conversation title and one for the conversation image. We have used a standard Bootstrap modal. Read their docs to learn more about it.

Adding a handler for the new action

At the top of our script.js file, we have two statements as shown below:

let conversationId = "";
const myModal = new bootstrap.Modal(
  document.getElementById("editModal"),
  {}
);

The first statement stores the value of the conversation ID inside a variable and the second line references the Bootstrap modal globally. We must now add a custom handler for the new action. We can do this with the onCustomConversationAction function:

chatbox.onCustomConversationAction("editTitleOrImage", (event) => {
  myModal.show();
  conversationId = event.conversation.id;
});

After clicking the custom action, we display the modal. When the custom action gets executed, it stores the conversation ID in the global variable. Inside the modal, we have a form with two input fields, one for the conversation title and the other for the image URL. Once you hit the submit button, we invoke the getFormData() method:

function getFormData(event) {
  event.preventDefault();
  const imageURL = document.getElementById("imageURL").value;
  const conversationTitle = document.getElementById("conversationTitle").value;
  editImageOrTitle(conversationId, imageURL, conversationTitle);
  myModal.hide();  
}

The first line prevents the page from reloading when you click the submit button. We then retrieve the values of both the text fields and invoke the editImageOrTitle() method passing the conversation ID, image URL, and conversation title as parameters. Finally, after calling the server endpoint, we hide the modal.

The editImageOrTitle()  method calls the server endpoint with the required data: the conversation ID as a mandatory parameter, followed by optional parameters for the title or image:

async function editImageOrTitle(conversationId, imageURL, conversationTitle) {
  const serverURL = `http://127.0.0.1:3000/editImageOrTitle`;
  const data = {
    conversationId: conversationId,
    conversationTitle: conversationTitle ? conversationTitle : undefined,
    imageURL: imageURL ? imageURL : undefined,
  };
  const response = await fetch(serverURL, {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(data),
  }).catch((err) => console.log(err));
}

We set the title and image based on what the user has entered.

Setting up the backend server

Next, we need to create a backend web server, which we’ll use to create a PUT endpoint for our custom action. We’ll be using Express in this tutorial, but feel free to use your favorite web server library instead. You'll also need to set up CORS support on your server. In this case, we'll use the cors package. The bodyParser dependency is used to read the requests we receive from the frontend and the dotenv dependency is used to read environment variables.

import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
app.use(cors())
app.use(bodyParser.json())
app.listen(3000, () => console.log("Server is up"));

Use the sample .env file provided in the code repository and paste the corresponding values from your TalkJS dashboard.

TALKJS_URL=https://api.talkjs.com/v1
APP_ID=<YOUR_APP_ID>
SECRET_KEY=<YOUR_SECRET_KEY>

Adding the endpoint for the custom action

The final step is to add the endpoint for our custom action. This endpoint retrieves the data from the frontend and calls the TalkJS REST API to update the conversation. In your server code, add the following:

async function editImageOrTitle(conversationId, imageURL, conversationTitle) {  
  let data = {};


  if (conversationTitle) {
    data.subject = conversationTitle;
  }
  if (imageURL) {
    data.photoUrl = imageURL;
  }
 
  const talkJSURL = `${process.env.TALKJS_URL}/${process.env.APP_ID}/conversations/${conversationId}`;
    
  const options = {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${process.env.SECRET_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(data),
  };
    
  const response = await fetch(talkJSURL, options).catch(err => console.log(err));
  console.log(response.status);
    
  return response;
}


app.put("/editImageOrTitle", async (req, res) => {
  const requestBody = await req.body;
  await editImageOrTitle(requestBody["conversationId"], requestBody["imageURL"], requestBody["conversationTitle"]);
  res.status(200).end();
});

From the PUT endpoint at /editImageOrTitle, we retrieve the conversationId, imageURL, and conversationTitle. We then invoke a function to call the TalkJS REST API with these values. In the first line of the async function, we check if either the imageURL or `conversationTitle` is empty and then set the data object accordingly.

Finally, we call the /v1/{appId}/conversations/{conversationId} endpoint with a PUT request so that the conversation gets updated. Note that you can enter both values at one go, or enter either of them one by one.

Check out the final output in action:

Demonstration of the finished feature. Clicking on the "Edit title or image" option brings up a modal where you can change the conversation title and image.
Demonstration of the finished feature

Note that we are using the Fetch API that is only available in Node 18+. If you’re using an earlier version of node, you can use the node-fetch package to use the Fetch API or axios to make HTTP requests.

Conclusion

With that, you now have a custom action for your conversation that lets you change the title or image of group conversations. To summarize, you have:

  • Added a new 'Edit title or image' custom conversation action.
  • Created a backend server and sent it your new conversation image and title.
  • Called TalkJS's REST API to update the conversation.

For the full example code for this tutorial, see our GitHub repo.

If you want to learn more about TalkJS, here are some good places to start:

You’ve successfully subscribed to TalkJS
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Your link has expired
Success! Check your email for magic link to sign-in.