Build a Chatbot with Phoenix and Api.ai - Part 2
Part 2
The goal of this section is to load and send messages. I think we can do it. Let’s get started. Setting up the Channel
We can see that our endpoint is already set up for us in lib/goldfish_web/endpoint.ex
:
defmodule GoldfishWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :goldfish
socket "/socket", GoldfishWeb.UserSocket
# ...
end
We need to also go into our user socket and uncomment the “room:*”. This will allow us to connect to room channels.
defmodule HelloWeb.UserSocket do
use Phoenix.Socket
## Channels
channel "room:*", HelloWeb.RoomChannel
...
Joining the RoomChannel
defmodule GoldfishWeb.RoomChannel do
use GoldfishWeb, :channel
def join("room:" <> session_id, payload, socket) do
{:ok, socket}
end
end
With that code for our backend, it is now time to get to work connecting to our channel using javascript. Open up assets/js/socket.js:
// assets/js/socket.js
...
socket.connect()
// Now that you are connected, you can join channels with a topic:
let channel = socket.channel("room:lobby", {})
channel.join()
.receive("ok", resp => { console.log("Joined successfully", resp) })
.receive("error", resp => { console.log("Unable to join", resp) })
export default socket;
We also need to make sure that we uncommented the line in assets/js/app.js to import our socket code.
import socket from “./socket”;
Creating a message
We need to make a few changes to make this happen. Let’s first open pages/index.html.eex and add:
<div id="messages"></div>
<input id="chat-input" type="text"></input>
The messages div will be a container for messages we send in this session. The chat-input will be our input field for typing out these messages. Alright, now let’s get to a bit of javascript. Open up assets/js/socket.js and add:
...
let channel = socket.channel(`room:${sessionId}`, {});
let chatInput = document.querySelector("#chat-input");
let messagesContainer = document.querySelector("#messages");
chatInput.addEventListener("keypress", event => {
if (event.keyCode === 13){
channel.push("new_msg", {body: chatInput.value});
chatInput.value = "";
}
})
channel.join()
.receive("ok", resp => { console.log("Joined successfully", resp) })
.receive("error", resp => { console.log("Unable to join", resp) })
export default socket
We also need a way to get the session_id to the front end. Right now it is stored as a cookie that our javascript does not have access to. An easy way to get this cookie is to set it as a global javascript variable. Open app.html.eex and add in the
:<head>
...
<script>
window.sessionId = '<%= assigns[:session_id] %>'
</script>
</head>
Handling incoming events
defmodule GoldfishWeb.RoomChannel do
use GoldfishWeb, :channel
def join("room:" <> room_id, payload, socket) do
{:ok, socket}
end
def handle_in("new_msg", %{"body" => body}, socket) do
broadcast!(socket, "new_msg", %{body: body})
{:noreply, socket}
end
end
Loading messages on page index
We are going to be loading messages by the session_id which we set in the last part.
defmodule Goldfish.Chat do
...
@doc """
Returns the list of messages.
## Examples
iex> list_messages(session_id)
[%Message{}, ...]
"""
def list_messages(session_id) do
query = from m in Message,
where: m.room_id == ^room_id,
order_by: [desc: m.inserted_at]
Repo.all(query)
end
end