Skip to content

Commit e5f71f1

Browse files
committed
Implement array input
1 parent fab505e commit e5f71f1

10 files changed

Lines changed: 136 additions & 13 deletions

File tree

assets/js/app.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,30 @@ import "phoenix_html"
1717
// paths "./socket" or full ones "web/static/js/socket".
1818

1919
// import socket from "./socket"
20+
21+
window.onload = () => {
22+
const removeElement = ({target}) => {
23+
let el = document.getElementById(target.dataset.id);
24+
let li = el.parentNode;
25+
li.parentNode.removeChild(li);
26+
}
27+
Array.from(document.querySelectorAll(".remove-form-field"))
28+
.forEach(el => {
29+
el.onclick = (e) => {
30+
removeElement(e);
31+
}
32+
});
33+
Array.from(document.querySelectorAll(".add-form-field"))
34+
.forEach(el => {
35+
el.onclick = ({target: {dataset}}) => {
36+
let container = document.getElementById(dataset.container);
37+
let index = container.dataset.index;
38+
let newRow = dataset.prototype;
39+
container.insertAdjacentHTML("beforeend", newRow.replace(/__name__/g, index));
40+
container.dataset.index = parseInt(container.dataset.index) + 1;
41+
container.querySelector("a.remove-form-field").onclick = (e) => {
42+
removeElement(e);
43+
}
44+
}
45+
});
46+
}

lib/many/accounts/accounts.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ defmodule Many.Accounts do
1919
"""
2020
def list_users do
2121
Repo.all(User)
22+
|> Repo.preload(:posts)
2223
end
2324

2425
@doc """

lib/many/blog/post.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ defmodule Many.Blog.Post do
44

55
schema "posts" do
66
field(:content, :string)
7-
field(:title, :string)
87

98
belongs_to(:user, Many.Accounts.User)
109

@@ -14,7 +13,7 @@ defmodule Many.Blog.Post do
1413
@doc false
1514
def changeset(post, attrs) do
1615
post
17-
|> cast(attrs, [:title, :content])
18-
|> validate_required([:title, :content])
16+
|> cast(attrs, [:content])
17+
|> validate_required([:content])
1918
end
2019
end

lib/many_web.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ defmodule ManyWeb do
4040
use Phoenix.HTML
4141

4242
import ManyWeb.ErrorHelpers
43+
import ManyWeb.InputHelpers
4344
import ManyWeb.Gettext
4445
alias ManyWeb.Router.Helpers, as: Routes
4546
end

lib/many_web/controllers/user_controller.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule ManyWeb.UserController do
1010
end
1111

1212
def new(conn, _params) do
13-
changeset = Accounts.change_user(%User{posts: [%Many.Blog.Post{}]})
13+
changeset = Accounts.change_user(%User{})
1414
render(conn, "new.html", changeset: changeset)
1515
end
1616

@@ -38,6 +38,7 @@ defmodule ManyWeb.UserController do
3838
end
3939

4040
def update(conn, %{"id" => id, "user" => user_params}) do
41+
user_params = Map.put_new(user_params, "content", nil)
4142
user = Accounts.get_user!(id)
4243

4344
case Accounts.update_user(user, user_params) do

lib/many_web/templates/user/form.html.eex

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,10 @@
99
<%= text_input f, :name %>
1010
<%= error_tag f, :name %>
1111

12-
<%= inputs_for f, :posts, [append: existing_records(@user)], fn post_f -> %>
13-
<%= label post_f, :title %>
14-
<%= text_input post_f, :title %>
15-
<%= error_tag post_f, :title %>
16-
12+
<%= inputs_for f, :posts, [append: existing_records(@conn)], fn post_f -> %>
1713
<%= label post_f, :content %>
18-
<%= textarea post_f, :content %>
14+
<%= array_input post_f, :content %>
15+
<%= array_add_button post_f, :content %>
1916
<%= error_tag post_f, :content %>
2017
<% end %>
2118

lib/many_web/templates/user/show.html.eex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<%= for post <- @user.posts do %>
1111
<li>
12-
<%= post.title %>
12+
<%= post.content %>
1313
</li>
1414
<% end %>
1515
</ul>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
defmodule ManyWeb.InputHelpers do
2+
use Phoenix.HTML
3+
4+
def array_input(form, field, attr \\ []) do
5+
default_attr = [
6+
count: 1
7+
]
8+
9+
merged_attr = attr ++ default_attr
10+
count = merged_attr[:count]
11+
values = [Phoenix.HTML.Form.input_value(form, field)] || []
12+
13+
values =
14+
if Enum.count(values) >= count,
15+
do: values,
16+
else: List.duplicate("", count - Enum.count(values)) ++ values
17+
18+
id = Phoenix.HTML.Form.input_id(form, field)
19+
20+
content_tag :ol,
21+
id: container_id(id),
22+
class: "input_container",
23+
data: [index: Enum.count(values)] do
24+
values
25+
|> Enum.with_index()
26+
|> Enum.map(fn {value, index} ->
27+
form_elements(form, field, value, index)
28+
end)
29+
end
30+
end
31+
32+
def array_add_button(form, field) do
33+
id = Phoenix.HTML.Form.input_id(form, field)
34+
# {:safe, content}
35+
content =
36+
form_elements(form, field, "", "__name__")
37+
|> safe_to_string
38+
39+
# |> html_escape
40+
data = [
41+
prototype: content,
42+
container: container_id(id)
43+
]
44+
45+
link("Add", to: "#", data: data, class: "add-form-field")
46+
end
47+
48+
defp form_elements(form, field, value, index) do
49+
type = Phoenix.HTML.Form.input_type(form, field)
50+
id = Phoenix.HTML.Form.input_id(form, field)
51+
new_id = id <> "_#{index}"
52+
53+
input_opts = [
54+
name: new_field_name(form, field, index),
55+
value: value,
56+
id: new_id,
57+
class: "form-control"
58+
]
59+
60+
content_tag :li do
61+
[
62+
apply(Phoenix.HTML.Form, type, [form, field, input_opts]),
63+
link("Remove", to: "#", data: [id: new_id], title: "Remove", class: "remove-form-field")
64+
]
65+
end
66+
end
67+
68+
defp container_id(id), do: id <> "_container"
69+
70+
defp new_field_name(form, field, index) do
71+
name = form.name |> String.slice(0..-4)
72+
"#{name}[#{index}][#{field}]"
73+
74+
# Phoenix.HTML.Form.input_name(form, field) <> "[]"
75+
end
76+
end

lib/many_web/views/user_view.ex

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
defmodule ManyWeb.UserView do
22
use ManyWeb, :view
33

4-
def existing_records(user) do
5-
if user.posts == [], do: [%Many.Blog.Post{}], else: []
4+
def existing_records(conn) do
5+
cond do
6+
Map.has_key?(conn.assigns, :user) and conn.assigns.user.posts == [] ->
7+
[%Many.Blog.Post{}]
8+
9+
Map.has_key?(conn.assigns, :user) and conn.assigns.user.posts != [] ->
10+
[]
11+
12+
not Map.has_key?(conn.assigns, :user) ->
13+
[%Many.Blog.Post{}]
14+
15+
true ->
16+
[]
17+
end
618
end
719
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule Many.Repo.Migrations.DropTextareaComments do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:posts) do
6+
remove(:title)
7+
end
8+
end
9+
end

0 commit comments

Comments
 (0)