基于嵌套形式的用户选择动态生成副本部分表单

时间:2016-10-13 15:53:32

标签: javascript jquery html ruby-on-rails forms

我尝试创建一个表单,根据用户的选择生成嵌套表单的副本。我有3个模型:可视化,其中有很多行,其中有很多窗格。

我希望能够允许用户单击一个小的下拉菜单,该菜单将生成一行,然后选择1,2或3个窗格。根据他们的选择,这将从渲染中生成他们选择的形式。

here is an example where a user chose 3 panes (3 upload boxes for images) with just styled divs in place of the form

首先。我知道我需要稍微改变一下我的控制器,但我不知道如何用嵌套的形式做到这一点,因为在我见过的每个例子中,你需要预先确定你有多少次会"建立"嵌套的模型表单(不确定这是否是正确的术语)。我不确定如何使这部分动态化。

这就是我的意思:



//visualization_controller.rb

def new
    @visualization = Visualization.new
    rows = @visualization.rows.build
    panes = rows.panes.build
  end




这是一个渲染示例,如果usr想要生成一个只有1个窗格的行,则会调用该渲染:



  <div class="medium-12 columns one_box_wrapper first" style="display:none">
    <%= f.fields_for :rows, Row.new do |r| %>
    <%= r.label :rowtitle %>
    <%= r.text_field :rowtitle %>
    <div class="nested" style="display:inline-block">
          <%= r.fields_for :panes, Pane.new do |p| %>
            <%= p.label :text %>
            <%= p.text_field :text %>
            <div class="mehv">
              <img id="img_prev" width=300 height=300 src="#" alt="your image" class="img-thumbnail hidden"/> <br/>
              <span class="meh">
                Upload Pane Image<%= p.file_field :pane_photo, id: "pane_photo" %>
              </span>
              <%= p.hidden_field :pane_photo_cache %>
            </div>
          <% end %>
      </ul>
    </div>
    <% end %>
  </div>
&#13;
&#13;
&#13;

这可能在铁轨中吗?我觉得javascript会起作用,但我不认为你可以通过JS渲染服务器端代码。

我对此感到有些不满,任何帮助都将不胜感激!

修改

我最终使用了cocoon gem,因为它似乎让我的生活变得更轻松了。但我无法在索引页面上获得所有显示的可视化效果!我不知道问题是什么..封面标题和图片显示但没有别的!

&#13;
&#13;
//schema.rb

  create_table "panes", force: :cascade do |t|
    t.integer "row_id",     null: false
    t.text    "text"
    t.string  "pane_photo"
  end

  create_table "rows", force: :cascade do |t|
    t.integer "visualization_id", null: false
    t.string  "rowtitle"
  end

  create_table "visualizations", force: :cascade do |t|
    t.string "title",       null: false
    t.string "cover_image"
  end
&#13;
&#13;
&#13;

&#13;
&#13;
//controller.rb

class VisualizationsController < ApplicationController
  before_action :authenticate_user!, except: [:index, :show]
  before_action :authorize_user, except: [:index, :show]
  helper_method :resource

  def index
    @visualizations = Visualization.all
    @visualization = Visualization.new
  end

  def new
    @visualization = Visualization.new
    rows = @visualization.rows.build
    panes = rows.panes.build
  end

  def create
    @visualization = Visualization.new(visualization_params)

    if @visualization.save
      redirect_to edit_visualization_path(@visualization)
    else
      render :new
    end
  end

  def edit
    @visualizations = Visualization.all
    @visualization = Visualization.find(params[:id])
  end

  protected

  def visualization_params
    params.require(:visualization).permit(:title, :cover_image, rows_attributes: [:visualization_id, :rowtitle, panes_attributes:[:text, :pane_photo]])
  end
&#13;
&#13;
&#13;

&#13;
&#13;
//index.html

<div class="visual_wrap text-center">
  <ul class="no-bullet text-center">
    <% @visualizations.each do |visualization| %>
    <li class="text-center">
      <div class="row visualization text-center">
        <%= image_tag visualization.cover_image.to_s, id: "visualization_image", class: "output_image" %>
        <p class="visualization_title"><%= visualization.title %></p>
        <a href="#" id="visualization_link"><p>+</p></a>
      </div>
      <div class="placeholder">
        <% visualization.rows.each do |row| %>
          <%= row.rowtitle %>
            <% row.panes.each do |p| %>
              <%= p.text %>
              <%= image_tag p.pane_photo.to_s, id: "pane_image", class: "output_image" %>
            <% end %>
        <% end %>
      </div>
    </li>
    <% end %>
  </ul>
</div>
&#13;
&#13;
&#13;

&#13;
&#13;
//new.html.erb

<% if user_signed_in? %>
<% if current_user.admin? %>
<div class="try">
  <div class="breadcrumb-wrapper">
    <ul class="breadcrumbs">
      <%= form_for @visualization, :html => {:multipart => true} do |f| %>
      <li><a href="#" class="preview button secondary">Preview</a></li>
      <li><div class="separating-bar">|</div>
        <li><input type="submit" name="commit" value="Save" class="save button secondary"></li>
      </ul>
    </div>
    <div class="cover_image text-center">
      <div class="row pre_img_prev">
        <div class="gray_bar"></div>
        <div class="img_prev">
          <img id="img_preview" src="#" alt="your image" class="img-thumbnail hidden text-center"/>
          <input type="text" name="visualization[title]" id="visualization[title]" class="inputtext" />
          <label for="visualization[title]" id="text_preview">+ Add Title</label>
          <div class="trash-can_title">
            <a href="#" id="trash-can_title"><i class="fa fa-trash fa-3x" aria-hidden="true"></i></a>
          </div>
        </div>
        <input type="file" name="visualization[cover_image]" id="visualization_cover_image" class="inputfile" />
        <label for="visualization_cover_image">+ Add Cover Image</label>
        <%= f.hidden_field :cover_image_cache %>
        <div class="trash-can_cover">
          <a href="#" id="trash-can_cover"><i class="fa fa-trash fa-3x" aria-hidden="true"></i></a>
        </div>
      </div>
    </div>
    <div class="row linkstest">
    <div class="rows">
      <%= f.fields_for :rows, Row.new do |task| %>
        <%= render 'row_fields', f: task %>
      <% end %>
      <div class="links">
        <%= link_to_add_association "Add Row", f, :rows %>
      </div>
    </div>
    <% end %>
    <% end %>
    <% end %>
  </div>
  </div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

你不需要真正需要JS,除了让它更多&#34; snappy&#34;。我认为你要找的是嵌套表格。

看看RaisCast它有点过时,但它是一个很好的基础。

您可能需要查看Cocoon gem以帮助您动态创建新字段。

Rails nested_form inside nested_form

<强>更新

如果您根本不想使用Javascript,则需要向控制器发出额外请求,告诉它为您初始化(构建)行和窗格,以便它呈现空的字段。视图。 例如:

def new
  @visualization = Visualization.new
  num_rows = params[:num_rows]
  num_rows.each { @visualization.rows.build }
end

您还需要在每行中包含窗格数,因此参数必须位于行属性中,例如params[:visualization][:rows][0][:num_panes],并使用该参数初始化行中的窗格。将该逻辑放在工厂服务中可能是最好的。

但是,如果使用JS创建空字段,则可以避免发出额外请求和所有逻辑。这是因为如果为其提供正确的属性,Rails将自动初始化(构建)行和窗格,例如:

{
  visualization: {
    rows_attributes: {
      # These are the attributes from an existing record
      0: {
        id: 39,
        panes_attributes: {
          0: {
            id: 992
          }
        }
      },
      # This is a new set of attributes for a new record
      # passed by the fields generated by cocoon where xxx
      # and yyy are random numbers
      xxxx: {
        panes_attributes: {
          yyyy: {
          }
        }
      }
    }
  }
}

然后您需要在控制器中执行的操作是:

def new
  # visualization_params are the permitted attributes
  @visualization = Visualization.new(visualization_params)
end