# Readme
`Spike.LiveView` provides a wrapper around
[Phoenix.LiveView](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html) and
[Phoenix.LiveComponent](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveComponent.html),
which simplifies working with memory-backed forms, including nested forms that require
contextual validation.
## Installation
[Available in Hex](https://hex.pm/packages/spike_liveview), the package can be installed
by adding `spike_liveview` to your list of dependencies in `mix.exs`:
```elixir
def deps do
  [
    {:spike_liveview, "~> 0.2"}
  ]
end
```
Documentation can be found at <https://hexdocs.pm/spike_liveview>.
## Quick start
Once installed in a Phoenix project, open up your `*_web.ex` file and add the following
functions:
```
  def form_live_view do
    quote do
      use Phoenix.LiveView,
        layout: {MyAppWeb.LayoutView, "live.html"}
      unquote(view_helpers())
      use Spike.LiveView
    end
  end
  def form_live_component do
    quote do
      use Phoenix.LiveComponent
      unquote(view_helpers())
      use Spike.LiveView
    end
  end
```
This allows you to build LiveViews and LiveComponents that ship with form and form erors handling
capabilities out of the box.
You will need a Spike form. For usage how to build these, refer to [Spike docs](https://hexdocs.pm/spike).
For example, your simplest possible registration form may look like this:
```
defmodule MyApp.RegistrationForm do
  use Spike.Form do
    field(:username, :string)
    field(:password, :string)
    validates(:username, presence: true, by: &__MODULE__.validate_not_taken/2)
    validates(:password, presence: true)
  end
  def validate_not_taken(value, _context) do
    if MyApp.Repo.get_by(MyApp.User, username: value) do
      {:error, "username already taken"}
    else
      :ok
    end
  end
end
```
And a LiveView to handle registration process would be:
```
defmodule MyAppWeb.RegistrationLive do
  use MyAppWeb, :form_live_view
  import Spike.LiveView.Components
  def mount(_params, _, socket) do
    form = MyApp.RegistrationForm.new(%{})
    {:ok,
     socket
     |> assign(%{form: form, errors: Spike.errors(form)})}
  end
  def render(assigns) do
    ~H"""
    <h1>Register</h1>
    <div>
      <label for="username">Username:</label>
      <.form_field field={:username} form={@form}>
        <input id="username" name="value" type="text" value={@form.username} />
      </.form_field>
      <.errors let={field_errors} field={:username} form={@form} errors={@errors}>
        <span class="error">
          <%= field_errors |> Enum.map(fn {_k, v} -> v end) |> Enum.join(", ") %>
        </span>
      </.errors>
    </div>
    <div>
      <label for="password">Password:</label>
      <.form_field field={:password} form={@form}>
        <input id="password" name="value" type="text" value={@form.password} />
      </.form_field>
      <.errors let={field_errors} field={:password} form={@form} errors={@errors}>
        <span class="error">
          <%= field_errors |> Enum.map(fn {_k, v} -> v end) |> Enum.join(", ") %>
        </span>
      </.errors>
    </div>
    <a href="#" phx-click="register">Register!</a>
    """
  end
  def handle_event("register", _, socket) do
    if socket.assigns.errors == %{} do
      # perform registration logic here
      IO.puts("Registering user with #{socket.assigns.form.username} and #{socket.assigns.form.password}....")
      {:noreply, socket}   
    else
      {:noreply, socket |> assign(:form, Spike.make_dirty(socket.assigns.form))}
    end
  end
end
```
Remember to mount it at router and visit <http://localhost:4000/register>:
```
  scope "/", MyAppWeb do
    pipe_through :browser
    live "/register", RegistrationLive
  end
```
Usage of form components provided by this library is, however, pretty low-level, and we
recommend you build your own form components instead.
For starting point to build your own form components,
see our [Components Library](components_library.md).
With the above components, we can shorten our `render/1` function:
```
  def render(assigns) do
    ~H"""
    <h1>Register</h1>
    <Input type="text" form={@form} field={:username} errors={@errors} />
    <Input type="passwod" form={@form} field={:} errors={@errors} />
 
    <a href="#" phx-click="submit">Register!</a>
    """
  end
```
And that's pretty sweet!
See [Components Library](components_library.md),
[Spike Example app](https://github.com/hubertlepicki/spike_example) for more examples.