动态添加新元素到特定列表

时间:2017-03-12 21:51:52

标签: javascript jquery ruby-on-rails sorting

在我的Rails 4应用程序中,我有一个Task模型,可以在多个不同的页面上以各种方式(按用户分组,按事务分组,按截止日期排序等等)进行排序/分组。用户可以从应用程序中的任何位置通过AJAX弹出模式创建新的Task,如果它们位于显示任务列表的页面上,我想在适当的时候将任务附加到列表中。 / p>

# NOTE: tasks should only ever be displayed one of the ways below, not multiple

# Displaying tasks grouped by user

<div id="user-1-tasks">
  <div class="task">...</div>
  ...
</div>
<div id="user-2-tasks">
  <div class="task">...</div>
  ...
</div>

# Displaying tasks grouped by transaction

<div id="transaction-1-tasks">
  <div class="task">...</div>
  ...
</div>
<div id="transaction-2-tasks">
  <div class="task">...</div>
  ...
</div>

# Displaying all tasks together (ordered by due date)

<div id="tasks">
  <div class="task">...</div>
  ...
</div>

确定要更新哪个正确列表的逻辑很复杂,因为页面上可能没有任何列表(没有更新),或者它可以用几种不同的方式排序,如上面列出的示例。这完全取决于用户在创建Task时所处的页面以及他们如何对任务进行排序(如果有)。

我提出了一个&#34; hack&#34;,我传递了所有可能按特定顺序更新的DOM ID,它会更新页面上正确的DOM ID,如果没有&#39则更新; t any。

计算用户当前正在查看的页面以及列表的排序方式很复杂,因此告诉JS更新&#34; all&#34;这些列表,知道DOM上一次只能存在1个。 DOM ID的顺序很重要,最后使用最具体的第一个和后备选项。

注意我正在使用服务器生成的JS通过Rails&#39; js.erb。我已经意识到围绕这种做法的讨论了,但是对于这个应用程序来说,在服务器上维护我的HTML模板的一个副本而不是尝试在客户端进行所有操作并来回传递JSON要清晰得多。 / p>

# app/models/task.rb
class Task < ApplicationRecord
  belongs_to :user
  belongs_to :transaction

  def domids_to_update
    "#transaction-#{transaction.id}-tasks, #user-#{user.id}-tasks, #tasks"
  end
end

# app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  # Only one of several pages that can display tasks a variety of ways
  def index
    if params[:sort] == "by-transaction"
      @tasks = Task.includes(:transaction).group_by(&:transaction_record)
    elsif params[:sort] == "by-user"
      @tasks = Task.includes(:user).group_by(&:user)
    else # default is order by due date
      @tasks = Task.order(:due_date)
    end
  end

  def create
    @task = Task.create(task_params.merge(user: current_user))
    # create.js.erb
  end

  private

  def task_params
    params.require(:task).permit(
      :title,
      :transaction_id,
      :due_date
    )
  end
end

# app/views/tasks/create.js.erb
$("<%= @task.domids_to_update %>").append("<%=j render(partial: 'tasks/task', locals: { task: @task } %>");

看起来很疯狂,这确实有效,因为&#34;应该&#34;一次只能显示在页面上的列表中的一个。

然而,当我做一些看似疯狂的事情时,通常是因为它们是。

有没有办法告诉jQuery(甚至是计划JavaScript)只更新@task.domids_to_update的第一次出现?返回的ID按特定顺序排列,最具体的是第一个,最后是全部。

或者是否有更好的方法来实现我想要实现的功能?

我慢慢地试图删除我的jQuery依赖项,所以我的偏好是vanilla JavaScript解决方案。我只需要支持现代浏览器,所以我不必担心IE6等。

或者如果通过计算适当的列表ID来解决服务器端的解决方案,我也可以对此进行更新。

1 个答案:

答案 0 :(得分:0)

您可以使用普通js检查元素是否存在,并将第一个现有元素分配给变量:

# app/models/task.rb
# first, in your assignment, lose the spaces and the hashes, 
# to make it simple to convert to array:
  def domids_to_update
    "transaction-#{transaction.id}-tasks,user-#{user.id}-tasks,tasks"
  end

# app/controllers/tasks_controller.rb
var ids = "<%= @task.domids_to_update %>".split(',')
var theElement = document.getElementById(ids[0]) || document.getElementById(ids[1]) || document.getElementById(ids[2])
if (theElement !== null)
    jQuery(theElement).append(...)
    // or with plain js:
        // var html = theElement.innerHTML
        // html = html + "appended html"
        // theElement.innerHTML = html
end