We need a way to be able to specify which chatroom to connect to for our polls-specific chat. To do that we'll need to start specifying the chatroom (we'll use that as part of the topic to connect to). We'll start by placing a data attribute on our chat-window in lib/vocial_web/templates/shared/_chat.html.eex that we will reference later in our chat.js file:
<div class="chat-window container well" id="enable-chat-channel" data-chatroom="<%= @chatroom %>">
We'll need to actually pass a value to that that will enable us to reference @chatroom since right now we're not setting that anywhere. We'll also need to hop out to our lib/vocial_web/templates/poll/show.html.eex and set that as part of the call to render:
<%= render(VocialWeb.SharedView, "_chat.html", messages: @poll.messages, chatroom: @poll.id) %>
This will currently break, as we're not including messages as a part of our preloads for our query, so we'll also need to hop over to lib/vocial_web/votes/votes.ex and change our get_poll/1 and list_polls/0 functions:
def get_poll(id) do
Repo.get!(Poll, id)
|> Repo.preload([:options, :image, :vote_records, :messages])
end
def list_polls do
Repo.all(Poll) |> Repo.preload([:options, :image, :vote_records, :messages])
end
We'll want to do the same in lib/vocial_web/templates/page/index.html.eex as well (this one being set to "lobby" instead of the poll's ID):
<%= render(VocialWeb.SharedView, "_chat.html", messages: @messages, chatroom: "lobby") %>
Next, we'll need to change the JavaScript code in assets/js/chat.js to use this new data attribute. We'll start off by getting that information out and putting that in our connect function, and we'll also change what channel we join by default:
// Get the chatroom that we're supposed to connect to
const chatroom = document
.getElementById("enable-chat-channel")
.getAttribute("data-chatroom");
// Create a channel to handle joining/sending/receiving
const channel = socket.channel("chat:" + chatroom);
Finally, we'll modify our join function for the Chat Channel module (in lib/vocial_web/channels/chat_channel.ex). We'll also need to modify our handle_in function to also be able to pull the poll_id (or lobby) out of the socket:
def join("chat:" <> _poll_id, _payload, socket) do
{:ok, socket}
end
Nothing special here! The last piece we need to do is flesh our handle_in function. It's mostly the same, but we'll start by pulling the poll_id out of the socket's topic (since it goes in the format of "chat:(poll ID or lobby)".
poll_id = case socket.topic do
"chat:lobby" -> nil
"chat:" <> id -> id
_ -> nil
end
Finally, we need to modify our create_message function in our with statement to pass in the poll ID:
with {:ok, _message} <- Votes.create_message(%{author: author, message: message, poll_id: poll_id}) do
The end result is that we should now have chats that are separate between the lobby and specific polls; we finally have that social edge to our application that we wanted to build! This is a pretty great portion of functionality and the kind of thing that allows us to really elevate our application!
Let's take a look at what the chat window looks like embedded in a Poll view, which should pretty closely match our original mockup: