在我的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来解决服务器端的解决方案,我也可以对此进行更新。
答案 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