A convenience library that allows you to further separate your views into scoped components.
Add viewplex to your list of dependencies in mix.exs:
def deps do
[
{:viewplex, "~> 0.3.0"}
]
endDocumentation can be be found at https://hexdocs.pm/viewplex.
Create new components by use-ing the Viewplex.Component module and creating a corresponding template with the same name:
lib/my_app_web/components/label_component.ex:
defmodule LabelComponent do
use Viewplex.Component
endlib/my_app_web/components/label_component.html.eex:
Hello World!You can also use inline templates:
defmodule LabelComponent do
use Viewplex.Component
def render(_assigns), do: ~E"Hello World"
endThen, call your component inside a template:
<%= component LabelComponent %>Remember to
import Viewplex.Helpersin your views.
Components should follow the same convention as Elixir modules.
So, if you have a MyAppWeb.Components.LabelComponent module, the file should be located at: my_app_web/components/label_component.ex. We also support (and encourage) prefixing the component module name with "Component", following the existant naming convention for Phoenix's views and controllers.
Like Structs, Components can also define fields:
defmodule LabelComponent do
use Viewplex.Component, [:message]
end<%= component LabelComponent, message: "Hello World" %>Fields defined in the component will be available as an assign in your template:
<label><%= @message %></label>
This should allow you to simply pass down a map of assigns that will be filtered before actually invoking the component:
<%= component LabelComponent, assigns %>
You can also pass aditional content to your components in two ways:
Inline:
<%= component LabelComponent, "Hello World" %>Or using do-blocks:
<%= component LabelComponent do %>
Hello World
<% end %>Content passed like this will be available as an assign under the :content key:
<label><%= @content ></label>Using named slots:
<%= component LabelComponent do %>
<% slot(:message, "Hello World") %>
<% end %><label><%= @slots.message ></label>Notice that we are using
<%instead of<%=. This is necessary because if you output the return of theslot/2function, you'll actually be rendering its content inside the component's block.
This happens because Viewplex will scan the component block forslot/2function calls and then extract the slot content so it is available in the template. This means that if you pre-render the slot in any form we won't be able to extract the proper values.
You can also customize how components are mounted by overriding the mount/1 function:
defmodule LabelComponent do
use Viewplex.Component, [:message]
def mount(assigns) do
user = Users.get_user(assigns.user_id)
{:ok, Map.put(assigns, :user, user)}
end
endOr disabling the component entirely by returning an {:error, reason} tuple:
defmodule LabelComponent do
use Viewplex.Component, [:message]
def mount(assigns) do
case Users.get_user(assigns.user_id) do
nil -> {:error, "could not fetch user"}
user -> {:ok, Map.put(assigns, :user, user)}
end
end
end- Improve documentation
- Add real use-cases as examples
- Improve function typespecs
- Publish to Hex
- Scaffold and setup tasks
- Component documentation generation
- Add test samples to README
- Log mount errors using Logger