Skip to content

Instantly share code, notes, and snippets.

@archonic
Last active March 23, 2021 21:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save archonic/5579208e6acba76020d359c1c9326d3c to your computer and use it in GitHub Desktop.
Save archonic/5579208e6acba76020d359c1c9326d3c to your computer and use it in GitHub Desktop.
Rails generic edit-in-place feature using Stimulus.
.row.no-gutters.attachment_item.my-3{ class: "resource_#{resource.id}", data: { controller: "edit-in-place", "edit-in-place-update-url": resource_path(resource.id), "edit-in-place-resource": "resource" } }
.col
%input{ type: :hidden, name: "attachment_detail[attachment_id]", value: file.id }
%h6
%span{ data: { target: "edit-in-place.input", fieldtype: "text", attr: "name", value: resource.name } }
%p
%span{ data: { target: "edit-in-place.input", fieldtype: "textarea", attr: "description", value: resource.description } }
.col-auto.pull-right
.btn-group{ role: "group" }
%button.btn.btn-sm{ type: "button", data: { action: "edit-in-place#editMode", target: "edit-in-place.editBtn" } }
= icon "pencil"
%button.btn.btn-sm{ type: "button", data: { action: "resources#removeResource", "resource-id": resource.id } }
= icon "trash"
import { Controller } from "stimulus"
export default class extends Controller {
static targets = ["input", "editBtn"]
connect() {
this.viewMode()
this.element.controller = this;
}
viewMode() {
this.inputTargets.forEach((element) => {
element.innerText = element.dataset.value ?? ""
})
}
editMode() {
this.inputTargets.forEach((element) => {
var input = document.createElement("input")
input.classList.add("edit-in-place")
input.setAttribute("type", element.dataset.fieldtype)
var name = `${this.data.get("resource")}[${element.dataset.attr}]`
input.setAttribute("name", name)
input.setAttribute("placeholder", element.dataset.attr)
input.setAttribute("value", element.innerHTML)
element.parentElement.replaceChild(input, element)
})
this.editBtnTarget.innerHTML = "<i style='font-size: 16px;' class='fa fa-save'></i>"
this.editBtnTarget.setAttribute("data-action", "edit-in-place#submit")
}
submit() {
let container = this.element
Rails.ajax({
url: this.data.get("update-url"),
data: this.formData(),
type: "patch",
beforeSend: function () {
return true;
},
success: function (response) {
container.parentElement.replaceChild(response.body, container)
},
error: function (response) {
container.classList.add("has-error")
}
});
}
formData() {
var virtualForm = document.createElement("form")
var inputs = this.element.querySelectorAll("input")
inputs.forEach(function(input) {
virtualForm.appendChild(input.cloneNode())
})
// https://stackoverflow.com/a/44033425/1686604
var data = Array.from(
new FormData(virtualForm),
e => e.map(encodeURIComponent).join('=')
).join('&')
return data
}
}
- resources.each do |resource|
= render partial: "index_item", locals: { resource: resource }
# frozen_string_literal: true
class ResourceController < ApplicationController
before_action :set_resource, only: :update
def update
authorize @resource
success = @resource.update resource_params
render partial: "resources/index_item",
locals: { resource: @resource },
status: success ? :ok : :bad_request
end
private
def set_resource
@resource = Resource.find( resource_params[:id] )
end
def resource_params
params.require(:resource).permit(
:id,
:attribute_1,
:attribute_2
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment