How to set up subfolder in MyApplib?

Dear all,

I try to figured out does Phoenix support subfolder → subfolder in folder lib such as :
lib
→ myapp_web
→ controller
→ subfolder (for controller and html.ex)
→ page_controller.ex
→ page_html.ex
→ subfolder (for html)
→ home.html.heex

image

I try this but showing error message, perhaps someone could help the right way. Tks

You want to post that here as well.

Generally elixir and phoenix do not care how you organize your files, but in phoenix certain features mostly around templates need to require knowledge around where related files are stored. Those might require change in configuration when you move them around.

3 Likes

image
this structures folder i try to create Sir

i got this error

[info] GET /frontend
[debug] Processing with MyappWeb.Backend.BlogController.index/2
  Parameters: %{}
  Pipelines: [:browser]
[info] Sent 500 in 61ms
[error] ** (UndefinedFunctionError) function MyappWeb.Backend.BlogController.index/2 is undefined or private

my code in router like :

  scope "/", MyappWeb do
    pipe_through :browser

    resources "/frontend", Backend.BlogController
  end

my code in blog_controller.ex like :

defmodule MyappWeb.Backend.BlogController do
	use MyappWeb, :controller

	def home(conn, _params) do
		render(conn, :home, layout: false)
	end
end

my code in blog_html.ex like :

defmodule MyappWeb.Backend.BlogHTML do
	use MyappWeb, :html

	embed_templates "frontend/*"
end

my code in blog_index.html.heex like :
<h1>Headline</h1>

Do i miss something ?

I am pretty sure, that embed_templates do not find your frontend directory (because how it would guess where to look). It either needs to be sibling directory of blog_html.ex or you need to specify full relative path (aka ../frontend).

3 Likes

please show me the right code Sir… T_T

embed_templates "../frontend/*"
1 Like

The error is saying it can’t find BlogController.index/2 which is true, you only have a home/2 function in there. I’m assuming you router has something like this:

get "/blog", BlogController, :index

You need to make an index/2.

Also, you will probably have to change render to:

render(conn, :blog_index)
1 Like

I just skip for a while and try to understand the guide from phoenix framework when create product.

When in the guides show us created product_html folder inside controller, the product_controller.ex and product_html.ex also inside in controller, so i try to make custom folder like this structure

image

but i got an error in product_html.ex line 12 “def product_form(assigns)” I don’t know how to solved this @hauleth , @sodapopcan , @LostKobrakai

Compiling 2 files (.ex)
    error: implementation not provided for predefined defp product_form (overridable 1)/1
    │
 12 │   def product_form(assigns)
    │       ^
    │
    └─ lib/myapp_web/controllers/backend/product/product_html.ex:12:7: MyappWeb.Backend.Product.ProductHTML (module)


== Compilation error in file lib/myapp_web/controllers/backend/product/product_html.ex ==
** (CompileError) lib/myapp_web/controllers/backend/product/product_html.ex: cannot compile module MyappWeb.Backend.Product.ProductHTML (errors have been logged)

my code in product_html.ex just like this :

defmodule MyappWeb.Backend.Product.ProductHTML do
  use MyappWeb, :html

  embed_templates "frontend/product/*"

  @doc """
  Renders a product form.
  """
  attr :changeset, Ecto.Changeset, required: true
  attr :action, :string, required: true

  def product_form(assigns)
end

For someone who is just starting on the guides, Phoenix is complicated enough when you’re staying on the “standard path”. Trying to force a nonstandard directory structure is going to make it harder to tell when you’re encountering a “learning the framework” problem versus a “custom organization” problem.

Beyond that, IMO the distinction doesn’t make a lot of sense - the code in the “frontend” directories is still compiled into functions that run 100% on the backend :man_shrugging:


As to your latest specific error:

The docs for Phoenix.Component.embed_templates suggest that this should work.

I was able to produce the same message without any Phoenix machinery at all:

defmodule Foo do
  defp foo_form(_arg), do: :ok
  defoverridable foo_form: 1

  def foo_form(_arg)
end

which gives the error:

** (CompileError) iex:8: implementation not provided for predefined def foo_form/1
    (elixir 1.13.0) src/elixir_erl_compiler.erl:12: anonymous fn/2 in :elixir_erl_compiler.spawn/1

However this doesn’t explain the error you’re seeing since embed_templates should be adding public functions, not private ones. :thinking:

1 Like

You can see my code in github here, perhaps you can see some my code probably wrong.

it’s solved,
my fault, just revise code in product_html.ex in :

embed_templates “…/…/frontend/product_html/*”

Tks Brother @sodapopcan the code you share i put additional like this

embed_templates “…/…/frontend/product_html/*”