Displaying rethinkDB tables in real time in Phoenix Framework

I'm trying to take a step back from my previous previous question about RethinkDB tables in Phoenix .

Now I am trying to get them by pipe so that new inserts to the table can be displayed in real time.

I already insert into the table via the handle_in function:

def handle_in("new_person", %{"firstName" => firstName, "lastName" => lastName}, socket) do
        broadcast! socket, "new_person", %{firstName: firstName, lastName: lastName}
    table("users")
    |> insert(%{first_name: firstName, last_name: lastName})
    |> RethinkExample.Database.run
    {:noreply, socket}
    end

      

And in app.js:

dbInsert.on("click", event => { //Detect a click on the dbInsert div (to act as a button)
  //Use a module from the channel to create a new person
  chan.push("new_person", {firstName: firstName.val(), lastName: lastName.val()});
  // Clear the fields once the push has been made
  firstName.val("");
    lastName.val("");
});

chan.join().receive("ok", chan => {
  console.log("Ok");
});

      

Which function should I use to handle:

table("users")
|> RethinkExample.Database.run

      

And how should I render the data if it is now a pipe and not html? I can display the inserted person using HTML + Javascript, but I want to get the new user from the DB and display it using other live table results.

This is how I am in sight: enter image description here

users.html.eex

<div class="jumbotron">
  <div id="userList">
    <%= for %{"first_name" => first_name, "last_name" => last_name} <- @users.data do %>
      <p><%= "#{first_name} #{last_name}" %>!</p>
    <% end %>
  </div>
</div>

<div class="dbOperation">
    First name: <input type="text" id="firstName"><br>
    Last name: <input type="text" id="lastName"><br>
    <div id="dbInsert">Insert</div>
    <br>
    <div id="userToInsert">User to insert: </div>
</div>

      

user_controller.ex

defmodule RethinkExample.UsersController do
  use RethinkExample.Web, :controller
  use RethinkDB.Query


    def users(conn, _params) do
    # List all elements of a table from the database
        q = table("users")
      # Query for filtering results:
            # |> filter(%{last_name: "Palmer"})
            |> RethinkExample.Database.run #Run the query through the database
        render conn, "users.html", users: q #Render users searched on the users template
    end
end

      

people_channel.ex

defmodule RethinkExample.PeopleChannel do
  use Phoenix.Channel
    use RethinkDB.Query

  #Handles the insert subtopic of people
  def join("people:insert", auth_msg, socket) do
    {:ok, socket}
  end

  # handles any other subtopic as the people ID, ie `"people:12"`, `"people:34"`
  def join("people:" <> _private_room_id, _auth_msg, socket) do
    {:error, %{reason: "unauthorized"}}
  end

    def handle_in("new_person", %{"firstName" => firstName, "lastName" => lastName}, socket) do
        broadcast! socket, "new_person", %{firstName: firstName, lastName: lastName}
    query = table("users")
    |> insert(%{first_name: firstName, last_name: lastName})
    |> RethinkExample.Database.run
    new_person = %{"id": hd(query.data["generated_keys"]), "firstName": firstName, "lastName": lastName}
    broadcast! socket, "new_person", new_person
    {:noreply, socket}
    end

    def handle_out("new_person", payload, socket) do
      push socket, "new_person", payload
      {:noreply, socket}
    end
end

      

app.js

import {Socket} from "phoenix"

let App = {
}

export default App

// Fetch fields from HTML through Jquery
let firstName = $("#firstName")
let lastName = $("#lastName")
let dbInsert = $("#dbInsert")
let userToInsert = $("#userToInsert")
let userList = $("#userList")

let socket = new Socket("/ws")  //Declare a new socket
socket.connect() //Connect to the created socket
let chan = socket.chan("people:insert", {}) //Assign the people insertion channel to the socket

dbInsert.on("click", event => { //Detect a click on the dbInsert div (to act as a button)
  //Use a module from the channel to create a new person
  chan.push("new_person", {firstName: firstName.val(), lastName: lastName.val()});
  // Clear the fields once the push has been made
  firstName.val("");
    lastName.val("");
})

chan.on("new_person", payload => {
  userToInsert.append(`<br/>[${Date()}] ${payload.firstName} ${payload.lastName}`);
  console.log("New Person", payload);
  userList.append(`<br><p> ${payload.firstName} ${payload.lastName}!</p>`);
})

chan.join().receive("ok", chan => {
  console.log("Ok");
})

      

+3


source to share


1 answer


You need a function handle_out

on your channel that you are listening to to insert. If you use broadcast_from!

then the sender will be excluded, if you use broadcast!

then the sender will also receive the message.

Add the following to your channel:

  def handle_out("new_person", payload, socket) do
    push socket, "new_person", payload
    {:noreply, socket}
  end

      

And the following to your JS client:

chan.on("new_person", payload => {
  console.log("New Person", payload);
});

      

Channel documentation is available at http://www.phoenixframework.org/docs/channels

change



When inserting a record into Rethink - the output looks like this:

%RethinkDB.Record{data: %{"deleted" => 0, "errors" => 0,
   "generated_keys" => ["7136199a-564b-42af-ad49-5c84cbd5b3e7"],
   "inserted" => 1, "replaced" => 0, "skipped" => 0, "unchanged" => 0}}

      

We know that the data you return from a rethink request looks like this:

{"first_name" => "John",
    "id" => "57c5d0d2-5285-4a24-a999-8bb7e2081661", "last_name" => "Smith"},

      

So - to broadcast a new entry to the browser, we want to replicate this data structure, so if you change the function handle_in

to:

def handle_in("new_person", %{"firstName" => first_name, "lastName" => last_name}, socket) do
  query = table("users")
  |> insert(%{first_name: firstName, last_name: lastName})
  |> RethinkExample.Database.run
  new_person = %{"id": hd(query.data["generated_keys"]), "first_name": first_name, "last_name": last_name}
  broadcast! socket, "new_person", new_person
  {:noreply, socket}
end

      

Then - if you follow the steps above with handle_out

and chat.on

, you will see the person logged out in your JavaScript console. From there - you can add it to your DOM using Javascript.

+3


source







All Articles