Morzaram

Morzaram

How to structure a large live view app?

Hey everyone,

I have a live view app that is slowly getting bigger and I’m really struggling to find a way to manage all of the logic for each page. Components, queries, page, etc.

I was hoping to get some insight on how I can best have file structure and other tips on making sure I can manage all the code for these things. Right now I feel that the contexts are getting in the way and I should be moving the queries in a file next to the page view itself.

Any insight and resources would be much appreciated!

Marked As Solved

kokolegorille

kokolegorille

I am suggesting a technique I learned from the book Absinthe/GraphQL..

For example…

  def list_requests_query(criteria \\ []) do
    query = from(p in Request)

    Enum.reduce(criteria, query, fn
      {:limit, limit}, query ->
        from p in query, limit: ^limit

      {:offset, offset}, query ->
        from p in query, offset: ^offset

      {:filter, filters}, query ->
        filter_with(filters, query)

      {:order, order}, query ->
        from p in query, order_by: [{^order, ^@order_field}]

      {:preload, preloads}, query ->
        from p in query, preload: ^preloads

      arg, query ->
        Logger.info("args is not matched in query #{inspect(arg)}")
        query
    end)
  end

  defp filter_with(filters, query) do
    Enum.reduce(filters, query, fn
      {:user_id, user_id}, query ->
        from q in query, where: q.user_id == ^user_id

      {:is_fetched, is_fetched}, query ->
        from q in query, where: q.is_fetched == ^is_fetched

      {:is_post_processed, is_post_processed}, query ->
        from q in query, where: q.is_post_processed == ^is_post_processed

      {:with_medium_path, true}, query ->
        from q in query, where: not is_nil(q.medium_path)

      {:with_medium_path, false}, query ->
        from q in query, where: is_nil(q.medium_path)

      arg, query ->
        Logger.info("args is not matched in query #{inspect(arg)}")
        query
    end)
  end

  def list_requests(criteria \\ []) do
    criteria
    |> list_requests_query()
    |> Repo.all()
  end

Using this, I could probably do something like…

        filter by location
        filter by category
        move to the next month
        move to the previous month
        show/hide the events that already have occured this month
        filter by the person who created the event

… and this would translate to

[filter: [by_location: location, by_category: category, by_month: month ...]]
|> App.list_requests()
17
Post #5

Also Liked

kokolegorille

kokolegorille

Instead of passing queries from web… can You pass criteria to the queries? I use the liveview to manage parameters I send to the query

I have one list_events function that do this only by passing parameters to the query. Do You have multiple queries instead?

mindok

mindok

Maybe I’m a heretic, but I’ve stopped using “Live” in any module (or folder) naming - most things are live now so it seems superfluous. Any non-live UI modules are controllers and/or views and named explicitly.

In the example above, I’d go:

lib/project_web/orders
  index.ex - ProjectWeb.Orders.Index
  view.ex - ProjectWeb.Orders.View
  edit.ex - ProjectWeb.Orders.Edit
  line_item_view_component.ex - ProjectWeb.Orders.LineItemView
  line_item_edit_form.ex - ProjectWeb.Orders.LineItemEdit

Any common logic related to the orders front end would get put in a module in that folder too.

Grouping everything around end user functionality makes it easier (IMO) to navigate between use wants, issues and bugs and the codebase.

Shared/generic components (buttons, progress bars, form fields etc) live in a components area at the top of the tree. Generally I put live components in a module to themselves, and function components grouped by general area of functionality.

lib/project_web/components
  forms.ex
  nav.ex
  datagrid.ex
  ...

As with most things, the biggest project I’m working on has archeology rather than architecture - there’s a few iterations of thinking about where to put things and not everything is in the right spot as yet.

lccezinha

lccezinha

I usually try to organize my code like this

- lib
-- project
---- orders
------ order.ex # schema
---- orders.ex # context
-- project_web
---- components # for shared/general components
------ header.ex
---- live
------ orders_live
-------- orders_live.ex # LV module handle in/out for info where heavy biz logic lives inside the context
-------- orders_live.html.heex
-------- component_related_to_orders_feature.ex

If that helps you.

If my context starts to grow I can extract into a smaller new module to handle queries, but I don’t do this that often.

Last Post!

kokolegorille

kokolegorille

Yes it is not so easy… but I could get some insight from this non-free course

Where Next?

Popular in Questions Top

vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40165 209
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42716 114
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement