简体   繁体   中英

How to create a double nested form in Phoenix Framework?

My issue is that I keep on getting an argument error when trying to add subsections to my interview form which is nested under sections.

The Interview_kit has many sections and sections have many sub_sections. The sections belong to the interview_kit and the subsections belong to the section.

I would like to create all of this in the same form but am haveing no luck.

Is it possible to do this in Phoenix?

 # Error 
 ArgumentError at GET /interview_Kit/new could not generate inputs for 
 :sub_sections from App.InterviewKit. Check the field 
 exists and it is one of embeds_one, embeds_many, has_one, has_many, 
  belongs_to or many_to_many

# This error is being shown when trying to render as a string in the method
  link_to_sub_sections_field() below

# fields = render_to_string(__MODULE__, "sub_section.html", f: form)

# Schemas 
schema "interview_kits" do
  field :name, :string
  field :description, :string
  has_many :sections, AppSection

  timestamps()
end

schema "sections" do
  field :title, :string
  timestamps()

  belongs_to :interview_kit, App.InterviewKit
  has_many :sub_sections, App.SubSection 
end

schema "sub_sections" do
  field :field_name, :string
  belongs_to :section, App.Section
end

defmodule App.InterviewKitView do
  def link_to_sub_section_fields()  do
    changeset = InterviewKit.changeset(%InterviewKit{sections: [%Section{sub_sections: [%SubSection{}]}]})
    form = Phoenix.HTML.FormData.to_form(changeset, [])
    fields = render_to_string(__MODULE__, "sub_section.html", f: form)
    link "Add Sub Section", to: "#", "data-template": fields, id: "add_sub_section"
  end
end 

# sub_sections.html.eex 
<%= inputs_for @f, :sub_sections, [multipart: true], fn fo -> %>
  <div class="row">
    <div class="col-md-11">
      <%= input fo, :field_name %>
    </div>
   <div class="col-md-1">
     <a href="#" id="delete_sub_section"><i class="fa fa-trash" aria-hidden="true"></i></a></h5>
    </div>
   </div>
<% end %>

# what I am trying to accomplish

interview_params = %{"_csrf_token" => "PDwZA==",
 "_utf8" => "✓", "files" => "",
 "interview_kit" => %{"description" => "<p>dsadasdasmoimoimadsads</p>",
 "name" => "First Interview", "sections" => %{"0" => %{"name" => "sadasdsad"},
                               "sub_sections" => %{"0" => %{"field_name" => "sadasdsad"}}}}}

Issue was I was not reiterating over the sections form in my sub_section.html.eex

# sub_section.html.eex 
# Correct way 
<%= inputs_for @f, :sections, [multipart: true], fn fo -> %>
  <div class="row">
    <div class="col-md-11">
      <%= inputs_for fo, :sub_sections, [multipart: true], fn po ->%>
        <%= input po, :field_name %>
      <% end %>
    </div>
    <div class="col-md-1">
      <a href="#" id="delete_sub_section"><i class="fa fa-trash" aria-hidden="true"></i></a></h5>
    </div>
  </div>
<% end %>

# sub_section.html.eex 
# Wrong way 
<%= inputs_for @f, :sub_sections, [multipart: true], fn fo -> %>
  <div class="row">
    <div class="col-md-11">
      <%= input fo, :field_name %>
    </div>
   <div class="col-md-1">
     <a href="#" id="delete_sub_section"><i class="fa fa-trash" aria-hidden="true"></i></a></h5>
    </div>
   </div>
<% end %>

# section.html.eex 
<%= inputs_for @f, :sections, [multipart: true], fn po -> %>
  <div class="row">
    <div class="col-md-12">
      <div class="panel panel-default">
        <div class="panel-heading">
          <div class="panel-title">
            <%= input po, :name  %>
          </div>
        </div>
        <div class="panel-body">
        <% inputs_for po, :sub_sections, [multipart: true], fn fo ->  %>
          <div class="row">
            <div class="col-md-11">
              <%= input fo, :field_name %>
             </div>
           </div>
          <% end %>
         <h5><a href="#"><%= link_to_sub_section_fields() %></a></h5>
        </div>
      </div>
      <!-- END PANEL -->
    </div>
    <%= link "Remove Section", to: "#", id: "delete_section" %>
  </div>
<% end %>  

#interview_kit_view.ex 
def link_to_sub_section_fields()  do
  changeset = InterviewKit.changeset(%InterviewKit{sections: [%Section{sub_sections: [%SubSection{}]}]})
  form = Phoenix.HTML.FormData.to_form(changeset, [])
  fields = render_to_string(__MODULE__, "sub_section.html", f: form)
  link "Add Sub Section", to: "#", "data-template": fields, id: "add_sub_section"
end 

interview_kit.js
  handleAdd() {
    $(document).on("click", "#add_section, #add_sub_section", function(e) {
      console.log($(e));
      e.preventDefault();
      let time = new Date().getTime();
      let template = $(this).data("template");
      let uniq_template = template.replace(/\[0\]/g, `[${time}]`);
      uniq_template = uniq_template.replace(/_0_/g, `_${time}_`);
      $(this).after(uniq_template);
    });
  }

I am not sure I fully understand why I have to reiterate over the sections form in my partial but it gives me the correct params on submit I was looking for.

%{"_csrf_token" => "AlgJcnNQw==",
  "_utf8" => "✓", "files" => "",
  "interview_kit" => %{"description" => "<p>dsadsadas</p>",
    "name" => "name",
    "sections" => %{"1495809951376" => %{"name" => "sadsadas",
        "sub_sections" => %{"1495809951376" => %{"name" => "field_param"}}}}}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM