Max Filippov
Max Filippov

Reputation: 2092

How can I dynamically add new nested field to form via JS in Rails?

I have model Post which has_many :relics and Relic which belongs_to :post. I have new post form, from where I can create Post's relics (multiple) as well (it works):

From new action in posts_controller.rb:

@post_relics = [@post.relics.build]*2

From _form.html.haml:

= f.fields_for :relics, @post_relics do |r|
  .more.group
    .photo
      = link_to 'Insert photo', '#', data: {toggle: 'upload'}
      = r.file_field :photo, accept: 'image/*'
    .fileds
      = r.label :title
      = r.text_field :title
      = r.label :description
      = r.text_field :description

My goal is to add 'Add more' button which will provide copy of .more div with valid input names and ids, how can I do that?

The above code renders in:

<div class='more group'>
  <div class='photo'>
    <a data-toggle="upload" href="#">Insert photo</a>
    <input accept="image/*" id="post_relics_attributes_0_photo" name="post[relics_attributes][0][photo]" type="file" />
  </div>
  <div class='fileds'>
    <label for="post_relics_attributes_0_title">Title</label>
    <input id="post_relics_attributes_0_title" name="post[relics_attributes][0][title]" type="text" value="" />
    <label for="post_relics_attributes_0_description">Description</label>
    <input id="post_relics_attributes_0_description" name="post[relics_attributes][0][description]" type="text" value="" />
  </div>
</div>
<input id="post_relics_attributes_0_id" name="post[relics_attributes][0][id]" type="hidden" value="6" />
<div class='more group'>
  <div class='photo'>
    <a data-toggle="upload" href="#">Insert photo</a>
    <input accept="image/*" id="post_relics_attributes_1_photo" name="post[relics_attributes][1][photo]" type="file" />
  </div>
  <div class='fileds'>
    <label for="post_relics_attributes_1_title">Title</label>
    <input id="post_relics_attributes_1_title" name="post[relics_attributes][1][title]" type="text" />
    <label for="post_relics_attributes_1_description">Description</label>
    <input id="post_relics_attributes_1_description" name="post[relics_attributes][1][description]" type="text" />
  </div>
</div>

Upvotes: 2

Views: 2495

Answers (3)

mmsilviu
mmsilviu

Reputation: 1461

You can use nested_form gem. An example, in this article.

Upvotes: 0

Max Filippov
Max Filippov

Reputation: 2092

The correct answer was given by some user, but someone deleted that answer - too bad. The answer was to use Cocoon gem, where everything is already implemented.

Upvotes: 0

nmarsh
nmarsh

Reputation: 164

Here's a quick solution using jQuery: http://jsfiddle.net/M4b9D/9/

function addMore() {
    var newdiv = $(".more_group:last").clone();
    var newid = Number(newdiv.attr('id').replace(/post_relics_attributes_(\d+)/, "$1")) + 1;

    newdiv.attr('id', "post_relics_attributes_" + newid)

    $.each(newdiv.find(":input"), function() {
      var thisname = $(this).attr('id');
       thisname = thisname.replace(/\d+/, newid);

       $(this).attr('name', thisname);
       $(this).attr('id', thisname);
       $(this).val('');
     });

    $("#groups").append(newdiv);

}

Basically, it just creates a copy of the last div inside a group of divs, and updates the ids/names/values of each input inside that div. I played a bit with the way your elements are named to make writing this a bit easier, as well as added a group div so there'd be something to append the new div to.

Upvotes: 1

Related Questions