Tutorials · · 7 min read

How to create a poll in TalkJS

This guide shows you how to create a poll in TalkJS and embed it in your chats.

How to create a poll in TalkJS

This guide shows you how to create a poll or questionnaire in TalkJS and embed it in your chats. We'll then use TalkJS's REST API to send a System Message from our backend server with the poll question. TalkJS's HTML Panels allow you to display a HTML document in your chats, just above the message field. We’ll use a panel to display the results of a poll, where users vote using custom action buttons.

Overview of a chat inbox with on the left side a list of conversations, and on the right side a chat window for the selected conversation. In the chat is a panel with a poll. The user clicks on of the poll options, and then selects the option 'End poll'. Once the poll has ended, the poll results are shown in the location where the poll question used to be.

To follow along, you’ll need:

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.

Ask users to vote in the poll

For our poll, we need to ask a question to the users in the chat along with the option for users to vote. To accomplish this in TalkJS, we’ll make a REST API call to create a System Message containing the question we want to show to all users. We need to call the REST API from a backend web server to avoid exposing our secret key in frontend code.

In this tutorial, we’ll use Express, but feel free to use your favorite web server library instead:

Let’s examine the code that accomplishes this:

await fetch(
    `${basePath}/v1/${appId}/conversations/${conversationId}/messages`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${secretKey}`,
      },
      body: JSON.stringify([
        {
          text: "Would you use TalkJS instead of developing your own chat solution?\n" +
          "<actionbutton:yesOrNo?choice=yes|Yes><actionbutton:yesOrNo?choice=no|No>" +
          "<actionbutton:yesOrNo?choice=end|End Poll>",
          type: "SystemMessage",
        },
      ]),
    }
  );

How it works:

1) Make a call to the Messages endpoint: ${basePath}/v1/${appId}/conversations/${conversationId}/messages. This allows you to send a message on behalf of a user, or a System Message. We’re sending a System Message in this case.

2) TalkJS allows you to add action buttons directly to messages. This is the method we use to create the buttons that allow our users to vote in the poll:

text: "Would you use TalkJS instead of developing your own chat solution?\n" +
"<actionbutton:yesOrNo?choice=yes|Yes><actionbutton:yesOrNo?choice=no|No>" +
"<actionbutton:yesOrNo?choice=end|End Poll>"

Let’s take a closer look at this snippet:

3) type: "SystemMessage": This value for type is what makes this message a System Message, as opposed to a UserMessage.

At this stage, we have asked our users the poll question, and now they have the option to vote:

Handling poll votes

Now that users can vote in polls, we need to track those votes and display the result when the poll has ended. To set this up, we’ll add an event handler for our action buttons, and some variables to keep track of how often each button was pressed.

yesVotes = 0;
noVotes = 0;

inbox.onCustomMessageAction('yesOrNo', (event) => {
  if (event.params.choice == 'end') {
     return;
  }
  else if (event.params.choice == 'yes') {
     yesVotes++;
  } 
  else if (event.params.choice == 'no') {
     noVotes++;
  }
});

Let’s break this down:

- We add two variables to keep track of votes: yesVotes and noVotes.

- Notice how our event handler uses the identifier yesAndNo that we mentioned earlier when we set up the action buttons: inbox.onCustomMessageAction('yesOrNo', (event) =>.

- In our event handler, we add a simple series of if statements to track user actions. The following occurs:

Our votes are now being tracked! The next step is to show the result of the poll when the poll is ended.

Displaying poll results

Let’s allow users to end the poll, and display the vote count when it ends. A simple way to do this is by adding an HTML Panel that will contain the results. First, we have to add the new HTML file for our panel and related CSS files to our project. See the code repository for this example to view these files.

The HTML file contains important snippets of code that need to be highlighted:

<body onload="loadVotes()">
    <div class = "poll-div">    
        <div class = "total">
            <p>Yes votes:</p><p id="yes-total">0</p>
            <p>No votes:</p><p id="no-total">0</p>
        </div> 
    </div>
</body>

Note the following:

In the same file, we define the loadVotes() function:

function loadVotes() {
        const queryString = window.location.search;
        const urlParams = new URLSearchParams(queryString);

        document.getElementById("yes-total").innerText = urlParams.get('yes');
        document.getElementById("no-total").innerText = urlParams.get('no');
    }

With this code:

Our HTML Panel is complete, but how do we show this panel at runtime when the poll is ended? Let’s get into it!

Go back to our original event handler code for the action buttons, specifically where we are listening for when the End Poll button is pressed:

if (event.params.choice == 'end') {
            return;
}

Update the code to the following:

if (event.params.choice == 'end') {
        var htmlPanelQuery= 'html-panel.html?yes=' + yesVotes + '&no=' + noVotes;
        inbox.createHtmlPanel({
              url: htmlPanelQuery,
              height: 100,
              show: true
          });
          return;
}

This code makes use of TalkJS’s HTML Panel feature. Let’s see how we deployed this feature for our use case:

inbox.createHtmlPanel({
	url: htmlPanelQuery,
	height: 100,
	show: true
});

To see the result of this work, simply click the End Poll button on the UI. You will see the totals for the votes displayed in the chat:

Great! We can see our poll results. However, the user should no longer be able to vote in the poll. Let’s add this functionality.

Deleting the System Message

To stop our users from voting in the poll after the poll has ended, we’ll make a call to the REST API to delete the message when the End Poll button is clicked.

Add this method to your HTML file:

async function postMessageId(messageId, conversationId) {
      const data = {
        messageId: messageId,
        conversationId: conversationId
      };
      // Send system message ID and conversation ID to your backend server
      const response = await fetch("http://localhost:3000/deleteSystemMessage", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(data),
      });
    }

This code takes in two parameters, messageId and conversationId, and sends this data to our NodeJS backend in a POST request.

Call this new method where our End Poll button is pressed:

if (event.params.choice == 'end') {
    await postMessageId(event.message.id, event.message.conversation.id);
    var htmlPanelQuery= 'html-panel.html?yes=' + yesVotes + '&no=' + noVotes;
    inbox.createHtmlPanel({
        url: htmlPanelQuery,
        height: 100,
        show: true
    });
        return;
}

We passed in the message ID and the conversation ID using the attributes of our event handler: await postMessageId(event.message.id, event.message.conversation.id); Our NodeJS backend code needs to be updated to handle this data that is being sent. Let’s work on that next!

First, create a method that calls the message deletion endpoint in TalkJS’s REST API:

async function deleteSystemMessage(messageId, conversationId) {
  console.log("Deleting message with id:", messageId);
  return fetch(`${basePath}/v1/${appId}/conversations/${conversationId}/messages/${messageId}`, {
    method: "DELETE",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${secretKey}`,
    },
  });
}

Now we just need to listen for the POST request from the front end. Let’s add the code to handle this:

app.post("/deleteSystemMessage", async (req, res) => {
  const { messageId, conversationId } = req.body;
  await deleteSystemMessage(messageId, conversationId);
  res.status(200).end();
});

This code reads the data that is sent from our HTML frontend when the End Poll button is clicked and calls our new deleteSystemMessage() method, which sends the request to TalkJS’s API. If your request was successful, you will see the System Message be deleted:


There you have it! A simple poll interface that makes use of some smart TalkJS features. Feel free to build upon this example, we can’t wait to see what you create!

Summary

In this tutorial, we have performed the following actions:

The tutorial provides code snippets and explanations for each step, enabling users to implement a simple yet effective poll interface within TalkJS chats. 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:

Read next