-
Notifications
You must be signed in to change notification settings - Fork 915
/
phoenix_component.ex
133 lines (99 loc) · 3.43 KB
/
phoenix_component.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
defmodule Phoenix.Component do
@moduledoc """
API for function components.
A function component is any function that receives
an assigns map as argument and returns a rendered
struct built with [the `~H` sigil](`Phoenix.LiveView.Helpers.sigil_H/2`).
Here is an example:
defmodule MyComponent do
use Phoenix.Component
# Optionally also bring the HTML helpers
# use Phoenix.HTML
def greet(assigns) do
~H"\""
<p>Hello, <%= assigns.name %></p>
"\""
end
end
The component can be invoked as a regular function:
MyComponent.greet(%{name: "Jane"})
But it is typically invoked using the function component
syntax from the `~H` sigil:
~H"\""
<MyComponent.greet name="Jane" />
"\""
If the `MyComponent` module is imported or if the function
is defined locally, you can skip the module name:
~H"\""
<.greet name="Jane" />
"\""
Learn more about the `~H` sigil [in its documentation](`Phoenix.LiveView.Helpers.sigil_H/2`).
## `use Phoenix.Component`
Modules that have to define function components should call `use Phoenix.Component`
at the top. Doing so will import the functions from both `Phoenix.LiveView`
and `Phoenix.LiveView.Helpers` modules.
Note it is not necessary to `use Phoenix.Component` inside `Phoenix.LiveView`
and `Phoenix.LiveComponent`.
## Assigns
While inside a function component, it is recommended to use
the functions in `Phoenix.LiveView` to manipulate assigns.
For example, let's imagine a component that receives the first
name and last name and must compute the name assign. One option
would be:
def show_name(assigns) do
assigns = assign(assigns, :name, assigns.first_name <> assigns.last_name)
~H"\""
<p>Your name is: <%= @name %></p>
"\""
end
However, when possible, it may be cleaner to break the logic over function
calls instead of precomputed assigns:
def show_name(assigns) do
~H"\""
<p>Your name is: <%= full_name(@first_name, @last_name) %></p>
"\""
end
defp full_name(first_name, last_name), do: first_name <> last_name
## Blocks
It is also possible to give HTML blocks to function components
as in regular HTML tags. For example, you could create a
button component that looks like this:
def button(assigns) do
~H"\""
<button class="btn">
<%= render_block(@inner_block) %>
</button>
"\""
end
and now you can invoke it as:
<.button>
This renders <strong>inside</strong> the button!
</.button>
In a nutshell, the block given to the component is
assigned to `@inner_block` and then we use
[`render_block`](`Phoenix.LiveView.Helpers.render_block/2`)
to render it.
You can even have the component give a value back to
the caller, by using `let`. Imagine this component:
def unordered_list(assigns) do
~H"\""
<ul>
<%= for entry <- @entries do %>
<li><%= render_block(@inner_block, entry) %></li>
<% end %>
</ul>
"\""
end
And now you can invoke it as:
<.unordered_list let={entry} entries={~w(apple banana cherry)}>
I like <%= entry %>
</.unordered_list>
"""
@doc false
defmacro __using__(_) do
quote do
import Phoenix.LiveView
import Phoenix.LiveView.Helpers
end
end
end