Fetch the <dialog>
contents when opened
Instead of calling render(template: "events/new")
within the
<dialog>
element, fetch that fragment dynamically through an
Asynchronous JavaScript and XML (AJAX ) request.
Since the <form>
element and its contents will be rendered on the
server, move the bulk#select
Stimulus action logic to the
EventsController#new
action and template. For example, instead of
using JavaScript to set an <input type="checkbox">
element’s checked
and autofocus
properties, render it with the checked
and autofocus
attributes.
Collapse app/controllers/events_controller.rb
Expand app/controllers/events_controller.rb
app/controllers/events_controller.rb
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
new file mode 100644
index 0000000..2f477f2
--- /dev/null
+++ b/app/controllers/events_controller.rb
@@ -0,0 +1,8 @@
+class EventsController < ApplicationController
+ def new
+ tasks = Task.all
+ selected_task = tasks.find_by(id: params[:task_id])
+
+ render layout: false, locals: {tasks: tasks, selected_task: selected_task}
+ end
+end
Collapse app/javascript/controllers/bulk_controller.js
Expand app/javascript/controllers/bulk_controller.js
app/javascript/controllers/bulk_controller.js
diff --git a/app/javascript/controllers/bulk_controller.js b/app/javascript/controllers/bulk_controller.js
index b1fb5d7..07bdb81 100644
--- a/app/javascript/controllers/bulk_controller.js
+++ b/app/javascript/controllers/bulk_controller.js
@@ -1,29 +1,23 @@
import { Controller } from "stimulus"
export default class extends Controller {
- static targets = [ "form" ]
-
- select({ currentTarget }) {
- const value = currentTarget.getAttribute(`data-${this.identifier}-value`)
- const input = this.inputTargets.find(input => input.value === value)
-
- if (input) {
- input.checked = true
- input.focus()
- }
- }
-
resetIfAllUnchecked() {
if (this.inputTargets.some(input => input.checked)) return
- this.resetForm()
+ this.reset()
}
- resetForm() {
+ reset() {
this.formTarget.reset()
}
get inputTargets() {
return Array.from(this.formTarget.elements)
}
+
+ get formTarget() {
+ const selector = `[data-${this.identifier}-target="form"]`
+
+ return this.element.querySelector(selector)
+ }
}
Collapse app/javascript/controllers/controls_dialog_controller.js
Expand app/javascript/controllers/controls_dialog_controller.js
app/javascript/controllers/controls_dialog_controller.js
diff --git a/app/javascript/controllers/controls_dialog_controller.js b/app/javascript/controllers/controls_dialog_controller.js
index c49099e..5a795db 100644
--- a/app/javascript/controllers/controls_dialog_controller.js
+++ b/app/javascript/controllers/controls_dialog_controller.js
@@ -1,7 +1,11 @@
import { Controller } from "stimulus"
export default class extends Controller {
- static targets = [ "dialog" ]
+ static targets = [ "dialog", "remoteFragment" ]
+
+ release() {
+ this.remoteFragmentTargets.forEach(form => form.reset())
+ }
showModal() {
this.dialogTarget.showModal()
Collapse app/javascript/controllers/remote_fragment_controller.js
Expand app/javascript/controllers/remote_fragment_controller.js
app/javascript/controllers/remote_fragment_controller.js
diff --git a/app/javascript/controllers/remote_fragment_controller.js b/app/javascript/controllers/remote_fragment_controller.js
new file mode 100644
index 0000000..91e3d2d
--- /dev/null
+++ b/app/javascript/controllers/remote_fragment_controller.js
@@ -0,0 +1,17 @@
+import { Controller } from "stimulus"
+
+export default class extends Controller {
+ static values = { outletSelector: String }
+
+ replace({ detail: [ response ] }) {
+ this.outletTargets.forEach(outlet => outlet.innerHTML = response.body.innerHTML)
+ }
+
+ remove() {
+ this.outletTargets.forEach(outlet => outlet.innerHTML = "")
+ }
+
+ get outletTargets() {
+ return document.querySelectorAll(this.outletSelectorValue)
+ }
+}
Collapse app/views/events/new.html.erb
Expand app/views/events/new.html.erb
app/views/events/new.html.erb
diff --git a/app/views/events/new.html.erb b/app/views/events/new.html.erb
index 9442652..744167e 100644
--- a/app/views/events/new.html.erb
+++ b/app/views/events/new.html.erb
@@ -1,5 +1,6 @@
<%= form_with scope: :event, url: completions_path, html: {
- autocomplete: :off, "data-bulk-target": "form", "data-action": "input->bulk#resetIfAllUnchecked"
+ autocomplete: :off, "data-bulk-target": "form",
+ "data-action": "input->bulk#resetIfAllUnchecked"
} do |form| %>
<fieldset>
<table>
@@ -8,14 +9,16 @@
<%= render "row", class: "absolute", "data-controller": "tethered",
"data-tethered-selector-value": "#" + dom_id(builder.object) do %>
<td>
- <%= builder.check_box class: "
- focus:shadow-outline
- form-checkbox
- h-6
- hover:shadow-outline
- text-yellow-500
- w-6
- " %>
+ <% (builder.object == selected_task).tap do |selected| %>
+ <%= builder.check_box checked: selected, autofocus: selected, class: "
+ focus:shadow-outline
+ form-checkbox
+ h-6
+ hover:shadow-outline
+ text-yellow-500
+ w-6
+ " %>
+ <% end %>
</td>
<td><%= builder.label %></td>
<% end %>
Collapse app/views/layouts/application.html.erb
Expand app/views/layouts/application.html.erb
app/views/layouts/application.html.erb
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 64d275b..4c7b939 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -14,7 +14,8 @@
<%= yield %>
</main>
- <dialog data-controller="dialog" data-controls-dialog-target="dialog" data-action="close->bulk#resetForm reset->dialog#close" class="
+ <dialog data-controller="dialog" data-controls-dialog-target="dialog"
+ data-action="close->bulk#reset close->controls-dialog#release reset->dialog#close" class="
backdrop:hidden
bg-transparent
border-0
@@ -22,7 +23,14 @@
p-0
w-full
">
- <%= render(template: "events/new", locals: {tasks: Task.all}) %>
+ <div data-remote-fragment-outlet-target></div>
+
+ <%= form_with url: new_event_path, id: :new_event_form, method: :get, html: {
+ "data-controller": "remote-fragment",
+ "data-controls-dialog-target": "remoteFragment",
+ "data-remote-fragment-outlet-selector-value": "[data-remote-fragment-outlet-target]",
+ "data-action": "ajax:success->remote-fragment#replace reset->remote-fragment#remove"
+ } %>
</dialog>
</body>
</html>
Collapse app/views/tasks/index.html.erb
Expand app/views/tasks/index.html.erb
app/views/tasks/index.html.erb
diff --git a/app/views/tasks/index.html.erb b/app/views/tasks/index.html.erb
index 61b2067..cf5debd 100644
--- a/app/views/tasks/index.html.erb
+++ b/app/views/tasks/index.html.erb
@@ -6,9 +6,9 @@
<% tasks.todo.each do |task| %>
<%= render "row", id: dom_id(task) do %>
<td>
- <%= render "button", id: dom_id(task, :select), type: :button, class: "form-checkbox h-6 w-6",
- "data-action": "click->bulk#select click->controls-dialog#showModal",
- "data-bulk-value": task.id do %>
+ <%= render "button", id: dom_id(task, :select), class: "form-checkbox h-6 w-6",
+ form: :new_event_form, name: :task_id, value: task.id,
+ "data-action": "click->controls-dialog#showModal" do %>
<span class="sr-only"><%= translate(".select") %></span>
<span class="sr-only" aria-hidden="true"><%= task.name %></span>
<% end %>
Collapse config/routes.rb
Expand config/routes.rb
config/routes.rb
diff --git a/config/routes.rb b/config/routes.rb
index 6a4097b..daf824b 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,5 +8,9 @@ Rails.application.routes.draw do
resources :reopenings, only: :create
end
+ constraints -> { _1.xml_http_request? } do
+ resources :events, only: :new
+ end
+
root to: "tasks#index"
end