在 Phoenix Framework 中实时显示 rethinkDB 表
Displaying rethinkDB tables in real time in Phoenix Framework
我正在尝试更进一步 。
现在我正尝试通过频道检索它们,以便实时显示 table 的新插入内容。
我已经通过 handle_in 函数插入到 table 中:
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
并且在 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");
});
我应该使用哪个函数来处理:
table("users")
|> RethinkExample.Database.run
如果数据现在是通道而不是 html,我应该如何呈现数据?
我可以用 HTML+Javascript 渲染插入的人,但我想要的是从数据库中检索新用户并用我的其他 table 结果实时渲染它。
以下是我在视觉上的看法:
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");
})
您需要在频道中使用 handle_out
功能来收听插入内容。如果您使用 broadcast_from!
那么发件人将被排除在外,如果您使用 broadcast!
那么发件人也会收到邮件。
将以下内容添加到您的频道:
def handle_out("new_person", payload, socket) do
push socket, "new_person", payload
{:noreply, socket}
end
并将以下内容发送给您的 JS 客户端:
chan.on("new_person", payload => {
console.log("New Person", payload);
});
频道文档位于 http://www.phoenixframework.org/docs/channels
编辑
在 Rethink 中插入记录时 - 输出如下所示:
%RethinkDB.Record{data: %{"deleted" => 0, "errors" => 0,
"generated_keys" => ["7136199a-564b-42af-ad49-5c84cbd5b3e7"],
"inserted" => 1, "replaced" => 0, "skipped" => 0, "unchanged" => 0}}
我们知道您从重新思考查询中得到的数据类似于:
{"first_name" => "John",
"id" => "57c5d0d2-5285-4a24-a999-8bb7e2081661", "last_name" => "Smith"},
所以 - 为了向浏览器广播新记录,我们想要复制这个数据结构,所以如果您将 handle_in
函数更改为:
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
然后 - 如果您使用 handle_out
和 chat.on
按照上述步骤操作,那么您将在 JavaScript 控制台中看到此人已注销。从那里 - 您可以使用 Javascript.
将其附加到您的 DOM
我正在尝试更进一步
现在我正尝试通过频道检索它们,以便实时显示 table 的新插入内容。
我已经通过 handle_in 函数插入到 table 中:
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
并且在 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");
});
我应该使用哪个函数来处理:
table("users")
|> RethinkExample.Database.run
如果数据现在是通道而不是 html,我应该如何呈现数据? 我可以用 HTML+Javascript 渲染插入的人,但我想要的是从数据库中检索新用户并用我的其他 table 结果实时渲染它。
以下是我在视觉上的看法:
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");
})
您需要在频道中使用 handle_out
功能来收听插入内容。如果您使用 broadcast_from!
那么发件人将被排除在外,如果您使用 broadcast!
那么发件人也会收到邮件。
将以下内容添加到您的频道:
def handle_out("new_person", payload, socket) do
push socket, "new_person", payload
{:noreply, socket}
end
并将以下内容发送给您的 JS 客户端:
chan.on("new_person", payload => {
console.log("New Person", payload);
});
频道文档位于 http://www.phoenixframework.org/docs/channels
编辑
在 Rethink 中插入记录时 - 输出如下所示:
%RethinkDB.Record{data: %{"deleted" => 0, "errors" => 0,
"generated_keys" => ["7136199a-564b-42af-ad49-5c84cbd5b3e7"],
"inserted" => 1, "replaced" => 0, "skipped" => 0, "unchanged" => 0}}
我们知道您从重新思考查询中得到的数据类似于:
{"first_name" => "John",
"id" => "57c5d0d2-5285-4a24-a999-8bb7e2081661", "last_name" => "Smith"},
所以 - 为了向浏览器广播新记录,我们想要复制这个数据结构,所以如果您将 handle_in
函数更改为:
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
然后 - 如果您使用 handle_out
和 chat.on
按照上述步骤操作,那么您将在 JavaScript 控制台中看到此人已注销。从那里 - 您可以使用 Javascript.