fbutano
List of nested maps not working from liveview
Hello, I have a small phoenix app with just one ecto model called Office with the following schema for parent relationship
defmodule Tree.Arma.Office do
use Ecto.Schema
import Ecto.Changeset
schema "offices" do
field :name, :string
belongs_to :parent, Tree.Arma.Office
has_many :children, Tree.Arma.Office
timestamps(type: :utc_datetime)
end
@doc false
def changeset(office, attrs) do
office
|> cast(attrs, [:id, :name, :parent_id])
|> validate_required([:name])
end
end
Inside Arma context I have the following helper function to retrieve a linear list of offices in parent-children relations and works perfectly
def list_descendants(id) do
base_query =
Office
|> where(id: ^id)
recursive_query =
Office
|> join(:inner, [next_descendant], parent in "descendants_list",
on: next_descendant.parent_id == parent.id
)
descendants_query = base_query |> union_all(^recursive_query)
{"descendants_list", Office}
|> recursive_ctes(true)
|> with_cte("descendants_list", as: ^descendants_query)
|> where([o], o.id != ^id)
|> Repo.all()
end
I have also defined the following functions to retrieve a nested map of descendants:
def nested_tree(parent_id) do
flat_list = list_descendants(parent_id)
nester(flat_list, parent_id)
end
def nester(flat_list, root_id) do
lookup = Enum.group_by(flat_list, & &1.parent_id)
with_children(root_id, lookup)
end
defp with_children(root_id, lookup) do
lookup
|> Map.get(root_id, [])
|> Enum.map(&nest_one(&1, lookup))
end
defp nest_one(row, lookup) do
%{row | children: with_children(row.id, lookup)}
end
So, if we have an Office with id=4 and call nested_tree(4) the function returns a nested map of all the descendants from the Office with id=4.
The problem is that when i call nested_tree from inside an iex -S mix shell all works fine; but when i the function is called from the liveview that shows the details for a sibgle Office, nested_tree() return an empty list. This is the code of the liveview:
defmodule TreeWeb.OfficeLive.Show do
use TreeWeb, :live_view
alias Tree.Arma
@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end
@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:office, Arma.get_office!(id))
|> assign(:office_tree, Arma.nested_tree(id))
}
end
defp page_title(:show), do: "Show Office"
defp page_title(:edit), do: "Edit Office"
end
I’ve found that if in the liveview the id of the office is hardcoded when calling nested_tree() it works!
So for example if in the liveview I put:
|> assign(:office_tree, Arma.nested_tree(4)
it works!
I’m really stuck with this, so if anybody can help me I really appreciate!!
Marked As Solved
nTraum
Then maybe passing the ID either as a string or as an integer is the reason for the different behaviour you observe.
The params map in the handle_params function always contains string values as far as I know. What happens if you parse to an integer before passing it to your functions?
@impl true
def handle_params(%{"id" => unsigned_id}, _, socket) do
id = String.to_integer(unsigned_id)
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:office, Arma.get_office!(id))
|> assign(:office_tree, Arma.nested_tree(id))
}
end
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









