Wesley Wen
Wesley Wen

Reputation: 81

How to create a nested input_for form in Phoenix framework?

how to use phoenix.html to create 3 tiers+ associated nested forms? something like

todo_list has_many todo_items has_many item_comments in one form?

same example as this blog a TodoList, with many TodoItems , but I was trying to accomplish one more relationship with TodoItems has_many ItemComments

TodoList model:

defmodule MyApp.TodoList do
  use MyApp.Web, :model

  schema "todo_lists" do
    field :title, :string            

    has_many :todo_items, MyApp.TodoItem

    timestamps
  end

  def changeset(model, params \\ :{}) do
    model
    |> cast(params, [:title])
    |> cast_assoc(:todo_items)
  end 
end

TodoItem model:

defmodule MyApp.TodoItem do
  use MyApp.Web, :model

  schema "todo_items" do
    field :body, :string

    belongs_to :todo_list, MyApp.TodoList
    has_many :item_comments, MyApp.ItemComment
    timestamps
  end

  def changeset(model, params \\ :{}) do
    model
    |> cast(params, [:body])
    |> cast_assoc(:item_comments)
  end
end

ItemComment model:

defmodule MyApp.ItemComment do
  use MyApp.Web, :model

  schema "item_comments" do
    field :body, :string

    belongs_to :todo_item, MyApp.TodoItem

    timestamps
  end

  def changeset(model, params \\ :{}) do
    model
    |> cast(params, [:body])
  end
end

the form for create todo list, but I am not sure how to put the item_comments into this form

<%= form_for @changeset, todo_lists_path(@conn, :create), fn f -> %>    
  <%= text_input f, :title %>  
  <%= inputs_for f, :todo_items, fn i -> %> 
    <%= text_input i, :body %> 
  <% end %>   
  <button name="button" type="submit">Create</button> 
<% end %>

for the controller I try to use include empty item_comment by default in the new action, and try to put another inputs_for inside the todo_items/inputs_for in the html form, but nothing works at all

changeset = TodoList.changeset(%TodoList{todo_items: [%MyApp.TodoItem{item_comments: [%MyApp.ItemComment{}]}]})

whats the proper way to do in this kind of form? and how to handle in controller new and create actions?

I have solved the create form problem in my own way, but will not work at the edit form, can anyone tell me the proper way to do it?

    changeset = TodoList.changeset(%TodoList{todo_items: [%MyApp.TodoItem{}, %MyApp.TodoItem{}]})

<%= form_for @changeset, todo_lists_path(@conn, :create), fn f -> %>    
  <%= text_input f, :title %>  
  <%= inputs_for f, :todo_items, fn i -> %> 
    <%= text_input i, :body %> 
    <%= inputs_for f, :todo_items, fn j -> %> 
      <%= text_input j, :param, name: "todo_list[todo_items][#{i.index}][item_comments][#{j.index}][body]" %>
    <% end %>  
  <% end %>   
  <button name="button" type="submit">Create</button> 
<% end %>

Upvotes: 2

Views: 4494

Answers (1)

Wesley Wen
Wesley Wen

Reputation: 81

<%= form_for @changeset, todo_lists_path(@conn, :create), fn f -> %>    
  <%= text_input f, :title %>  
  <%= inputs_for f, :todo_items, fn i -> %> 
    <%= text_input i, :body %> 
    <%= inputs_for i, :todo_items, fn j -> %> 
      <%= text_input j, :item_comments %>
    <% end %>  
  <% end %>   
  <button name="button" type="submit">Create</button> 
<% end %>

correct answer

Upvotes: 4

Related Questions