Skip to content

Instantly share code, notes, and snippets.

@tetiana12345678
Last active November 8, 2017 15:42
Show Gist options
  • Save tetiana12345678/2e7bbad411eccf6fb433949c857c6b5b to your computer and use it in GitHub Desktop.
Save tetiana12345678/2e7bbad411eccf6fb433949c857c6b5b to your computer and use it in GitHub Desktop.
Building a chat app with Elixir and Phoenix

Create new umbrella application

$ mix new chatter --umbrella
$ cd chatter

Create new Phoenix Project

$ cd apps
$ mix phx.new.web chatter_web

Note: choose Y for fetch or install dependencies question.

Go into your application by running:

$ cd chatter_web

Start your Phoenix app with:

$ mix phx.server

You can also run your app inside IEx (Interactive Elixir) as:

$ iex -S mix phx.server

Check It Out!

Navigate to localhost:4000 to see server running with initial setup provided by Phoenix.

Chat app view

Let's create a chat app view, which will display messages posted to the chat as well as fields to type your username and message. Replace content of the chatter/apps/chatter_web/lib/chatter_web/templates/page/index.html.eex file with

<div id="messages"></div><br/>

<div class="col-md-2 form-group">
  <label>Username</label>
  <input id="username" type="text" class="form-control" placeholder="username" />
</div>

<div class="col-md-10 form-group">
  <label>Message</label>
  <input id="message" type="text" class="form-control" />
</div>

Add channel

In chatter/apps/chatter_web/lib/chatter_web/channels/user_socket.ex uncomment line which sets up channel.

channel "room:*", ChatterWeb.RoomChannel

Note: ChatterWeb.RoomChannel is the name of the module where channel logic will go.

Create new file

(chatter/apps/chatter_web)$ touch lib/chatter_web/channels/room_channel.ex

and add channel logic:

defmodule ChatterWeb.RoomChannel do
  use Phoenix.Channel

  def join("room:lobby", _payload, socket) do
    {:ok, socket}
  end

  def handle_in("new_message", payload, socket) do
    broadcast! socket, "new_message", payload
    {:noreply, socket}
  end
end

JavaScript

Replace all content in the file chatter/apps/chatter_web/assets/js/app.js with:

import {Socket} from "phoenix"

const socket = new Socket("/socket")
socket.connect()

const init = (socket, document) => {
  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) })

  let username = document.getElementById("username")
  let message = document.getElementById("message")
  let messages = document.getElementById("messages")

  message.addEventListener("keypress", keyPressHandler(username, message, channel))

  channel.on("new_message", renderMessage(messages))
}

const keyPressHandler = (username, message, channel) => {
  return (event) => {
    if (event.charCode == 13) {
      channel.push("new_message", {
        user: username.value,
        body: message.value
      })
      message.value = ""
    }
  }
}

const renderMessage = (messages) => ({user, body}) => {
  const new_message = `<p><b>[${user}]</b>:${body}</p>`
  messages.insertAdjacentHTML('beforeend', new_message)
}

init(socket, document)

Voila! Enjoy your chat app. Open few tabs for multiuser experience.

What's next?

By creating an umbrella application in step 1, we left some room to extend current functionality. What could be next steps:

  • create another application within the umbrella
  • add new functionality to newly created application
  • add newly created application with new functionality as a dependency to our chat application.
@ktec
Copy link

ktec commented Oct 8, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment