2017-03-12 3 views
0

In meiner Rails 4-Anwendung habe ich ein Task Modell, das auf verschiedene Arten sortiert/gruppiert werden kann (Gruppe für Benutzer, Gruppe für Transaktion, Reihenfolge nach Fälligkeit, etc ...) verschiedene Seiten. Benutzer können ein neues Task über ein AJAX-Popup-Modal von überall in der Anwendung erstellen, und wenn sie sich auf einer Seite befinden, auf der eine Liste von Aufgaben angezeigt wird, möchte ich die Aufgabe gegebenenfalls der Liste hinzufügen.Dynamisches Hinzufügen eines neuen Elements zu einer bestimmten Liste

# 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> 

Die Logik für die Aktualisierung, die richtige Liste zu bestimmen, ist komplex, weil es keine Liste auf der Seite sein kann (kein Update) oder es könnte ich oben auf verschiedene Weise, wie die Beispiele sortiert auflisten. Alles hängt davon ab, auf welcher Seite der Benutzer war, als er die Task erstellte und wie sie ihre Aufgaben sortiert hatten (falls vorhanden).

Ich kam mit einem "Hack", wobei ich alle möglichen DOM-IDs übergebe, die in einer bestimmten Reihenfolge aktualisiert werden können, und es aktualisiert das richtige auf der Seite, oder keines, wenn es keine gibt.

Die Berechnung der Seite, die der Benutzer gerade betrachtet und wie die Liste sortiert ist, ist kompliziert, daher schien es viel einfacher zu sein, dem JS mitzuteilen, "alle" Listen zu aktualisieren, da nur 1 im DOM vorhanden sein sollte eine Zeit. Die Reihenfolge der DOM-IDs ist wichtig, wobei die spezifischste Option zuerst und die Option Fallback zuletzt verwendet wird.

Hinweis Ich verwende servergenerierte JS über Rails 'js.erb. Ich bin mir der Diskussion darüber bewusst, aber für diese Anwendung war es viel sauberer, eine Kopie meiner HTML-Vorlagen auf dem Server zu behalten, anstatt zu versuchen, alles auf der Client-Seite zu machen und JSON vor und zurück zu übergeben.

# 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 } %>"); 

So verrückt wie es scheint, das tatsächlich funktioniert, weil es „sollte“ nur 1 der Listen zu einem Zeitpunkt auf der Seite vorhanden sein.

Wenn ich jedoch Dinge mache, die verrückt scheinen, dann ist es meistens so, weil sie es sind.

Gibt es eine Möglichkeit, jQuery (oder sogar mit Plan-JavaScript) nur das erste Auftreten des @task.domids_to_update zu aktualisieren? Die zurückgegebenen IDs sind in einer bestimmten Reihenfolge angeordnet, mit dem spezifischsten ersten und dem Catch-All am Ende.

Oder gibt es eine bessere Möglichkeit, die Funktionalität zu implementieren, die ich erreichen möchte?

Ich versuche langsam, meine jQuery Abhängigkeit zu entfernen, so dass meine Vorliebe Vanille JavaScript-Lösungen ist. Ich muss nur moderne Browser unterstützen, also muss ich mich nicht um IE6 usw. kümmern.

Oder, wenn die Lösung serverseitig aufgelöst wird, indem man die passende Listenidentifikation berechnet, um zu aktualisieren, bin ich dazu auch offen .

+0

Soweit mir bekannt ist, unter Verwendung von ID als Wähler nur die erste tatsächliche Auftreten auf die auswirken DOM. Oder du könntest zuerst nach '#this_id fragen: zuerst, #that_id: first' –

+0

Oder wenn du zuerst eines willst, benutze' .first() ' –

+0

@RubyRacer: Ich war mehr besorgt darüber, die zweite/dritte IDs I zu aktualisieren übergeben Sie es lieber als mehrere Instanzen der gleichen ID. Zum Beispiel mache ich mir Sorgen, dass '$ (" # id-1, # id-2, # id-3 "). Append (...)' würde '# id-1' UND' # id-2 aktualisieren '; aber das ist es, was es tun soll. Ich habe versucht zu sehen, ob es einen Weg gab, dass dieser Code NUR auf der ersten gefundenen ID laufen würde.Wenn sich zum Beispiel '# id-2' und' # id-3' im DOM befinden, würde es nur '# id-2' aktualisieren und keine anderen. –

Antwort

0

Man könnte glatt js verwenden für Element Existenz zu überprüfen und das erste vorhandene Element einer Variablen zuweisen:

# 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 
Verwandte Themen