README.md

# Readme

[Spike](https://github.com/hubertlepicki/spike) helps you build stateul,
server-memory backed forms in Elixir.

If you are struggling with making deep nested Ecto changesets back your forms
the way you like it, you may have ended up in a right place.

## Installation

[Available in Hex](https://hex.pm/packages/spike), the package can be installed
by adding `spike` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:spike, "~> 0.2"}
  ]
end
```

Documentation can be found on [HexDocs](https://hexdocs.pm/spike).

## Usage

Spike can be used on it's own, or with
[Phoenix LiveView](https://github.com/phoenixframework/phoenix_live_view) /
[Surface UI](https://surface-ui.org/).

Basic usage consists on creating an Elixir module, which represents your form
and stores both: data, that the user can manipulate using UI controls
(via LiveView or otherwise), and data that is necessary for the form to be
rendered and displayed to user.

Spike's [LiveView bindings](https://github.com/hubertlepicki/spike-liveview) or
[Surface UI bindings](https://github.com/hubertlepicki/spike-surface) can be
used together with this core library to extend live views or components with
out-of-the box support for `@form` and `@errors`, as well as default
implementation of events handling, to build

Spike forms are based on Elixir structs, that declare fields, associations and
validations - similar to Ecto schemas or ActiveRecord models. These forms,
however, live entirely in the memory. Let's consider a registration form. We
have to define a module, with fields and validations:

```
defmodule MyApp.RegistrationForm do
  use Spike.Form do
    field(:first_name, :string)
    field(:last_name, :string)
    field(:age, :integer)
    field(:email, :string)
    field(:accepts_conditions, :boolean, default: false)
  end

  validates(:first_name, presence: true)
  validates(:accepts_conditions, acceptance: true)
end
```

```
form = MyApp.RegistrationForm.new(%{})
Spike.valid?(form)
=> false
Spike.errors(form)[form.ref]
=> %{accepts_conditions: [acceptance: "must be accepted"], first_name: [presence: "must be present"]}
```

See the documentation for `Spike`, `Spike.Form`,
and `Spike.Form.Schema` modules for usage and examples.

For more complete example of usage with LiveView and Surface UI, have a look at our [example application](https://spikeexample.fly.dev/).