LiveVue
1.0
Examples
Dynamic Arrays
Dynamic Arrays
Use fieldArray()
to manage dynamic lists with add, remove, and per-item validation.
What this example shows
1
fieldArray()
form.fieldArray("tags")
2
Add & Remove
tagsArray.add(), .remove(i)
3
Per-Item Errors
tags[0], tags[1] validation
array_form_live.ex
defmodule MyAppWeb.ArrayFormLive do
use MyAppWeb, :live_view
import Ecto.Changeset
defmodule Tag do
use Ecto.Schema
import Ecto.Changeset
@derive LiveVue.Encoder
@primary_key false
embedded_schema do
field :name, :string
end
def changeset(tag, attrs) do
tag
|> cast(attrs, [:name], empty_values: [])
|> validate_required([:name])
|> validate_length(:name, min: 2, max: 30)
end
end
defmodule Post do
use Ecto.Schema
import Ecto.Changeset
@derive LiveVue.Encoder
@primary_key false
embedded_schema do
field :title, :string
embeds_many :tags, Tag, on_replace: :delete
end
def changeset(post, attrs) do
post
|> cast(attrs, [:title])
|> validate_required([:title])
|> validate_length(:title, min: 2, max: 100)
|> cast_embed(:tags, with: &Tag.changeset/2)
end
end
def render(assigns) do
~H"""
<.vue
form={@form}
submitted={@submitted}
v-component="ArrayForm"
v-socket={@socket}
/>
"""
end
def mount(_params, _session, socket) do
changeset = Post.changeset(%Post{}, %{})
{:ok, assign(socket, form: to_form(changeset, as: :post), submitted: nil)}
end
def handle_event("validate", %{"post" => params}, socket) do
changeset =
%Post{}
|> Post.changeset(params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, form: to_form(changeset, as: :post))}
end
def handle_event("submit", %{"post" => params}, socket) do
changeset =
%Post{}
|> Post.changeset(params)
|> Map.put(:action, :insert)
if changeset.valid? do
data = Ecto.Changeset.apply_changes(changeset)
{:reply, %{reset: true},
socket
|> assign(submitted: data)
|> assign(form: to_form(Post.changeset(%Post{}, %{}), as: :post))}
else
{:noreply, assign(socket, form: to_form(changeset, as: :post))}
end
end
end
How it works
1 Define an embedded schema or relation
Use embeds_many
or has_many
to define array items. Each item gets its own changeset and validation.
defmodule Tag do
use Ecto.Schema
@derive LiveVue.Encoder
embedded_schema do
field :name, :string
end
end
embeds_many :tags, Tag, on_replace: :delete
2 Get an array field reference
Use
form.fieldArray("tags")
to get a reactive array with add, remove, and iteration capabilities. Nested access is supported.
const tagsArray = form.fieldArray("tags")
// Add a new tag object
tagsArray.add({ name: '' })
// Remove tag at index
tagsArray.remove(index)
3 Iterate and access nested fields
Loop over
tagsArray.fields.value
and use
tagField.field('name')
to access each item's properties with full error support.
<div v-for="(tagField, index) in tagsArray.fields.value" :key="index">
<input v-bind="tagField.field('name').inputAttrs.value" />
<div v-if="tagField.field('name').errorMessage.value">
{{ tagField.field('name').errorMessage.value }}
</div>
<button @click="tagsArray.remove(index)">Remove</button>
</div>
4 Use cast_embed for validation
Call
cast_embed(:tags)
to automatically validate each item using its own changeset. Errors are mapped per-item.
def changeset(post, attrs) do
post
|> cast(attrs, [:title])
|> validate_required([:title])
|> cast_embed(:tags, with: &Tag.changeset/2)
end
Next up: File uploads with useLiveUpload()
View example →