Skip to content

Instantly share code, notes, and snippets.

@julianrubisch
Last active September 8, 2018 08:58
Show Gist options
  • Save julianrubisch/c733d72f6bad9233d9f7bbaf95db525a to your computer and use it in GitHub Desktop.
Save julianrubisch/c733d72f6bad9233d9f7bbaf95db525a to your computer and use it in GitHub Desktop.
DRY up an Inline-Text-Edit component with Partials, Capture, and a StimulusJS controller
- downcase_modelname = model.class.name.downcase
- url = Rails.application.routes.url_helpers.send("#{downcase_modelname}_path", model, format: :json)
div[class="#{wrapper_class}" data-controller="inline-edit" data-inline-edit-url="#{url}" data-inline-edit-model="#{downcase_modelname}" data-inline-edit-model-attribute="#{attribute}" data-inline-edit-model-id="#{model.id}"]
span[data-target="inline-edit.originalText" id="#{attribute}-original"]
span = capture(attribute, &block)
a.inline-edit-edit-button[data-action="inline-edit#handleShow"]
i.fas.fa-edit
= simple_fields_for model do |f|
.ui.form.mini.hidden[data-target="inline-edit.form" id="#{attribute}-form"]
.ui.inline.fields
= f.input attribute, wrapper_html: { class: 'twelve wide field' }, input_html: { data: { action: 'keydown->inline-edit#handleKeyUp', target: 'inline-edit.textField' } }, label: false
= f.button :button, class: 'ui negative mini icon button', data: { action: 'inline-edit#handleCancel' } do
i.fas.fa-times
= f.button :button, class: 'ui positive mini icon button', data: { action: 'inline-edit#handleSubmit' } do
i.fas.fa-check
.ui.red.pointing.above.label.error.hidden.inline-edit-error-label[data-target="inline-edit.errorLabel"]
.inline-edit-edit-button {
margin-left: 1rem;
}
.inline-edit-error-label {
margin-top: -1rem !important;
}
[data-controller="inline-edit"] {
.hidden {
display: none;
}
}
# from https://stackoverflow.com/a/27367024/4341756
def inline_edit_form_for(model, attribute, wrapper_class, &block)
render partial: 'common/inline_text_edit',
locals: {
model: model,
attribute: attribute,
wrapper_class: wrapper_class,
block: block
}
end
import { Controller } from "stimulus";
import Rails from 'rails-ujs';
export default class extends Controller {
static targets = [ 'form', 'originalText', 'textField', 'errorLabel' ];
handleShow(e) {
e.preventDefault();
this._showForm();
}
handleCancel(e) {
e.preventDefault();
this.textFieldTarget.value = this.originalTextTarget.querySelector('.inline-text-edit-target').innerText;
this.clearAndHide();
}
clearAndHide() {
this.textFieldTarget.parentElement.classList.remove('error');
this.errorLabelTarget.classList.add('hidden');
this._hideForm();
}
handleSubmit(e) {
e.preventDefault();
this._submitForm();
}
_hideForm() {
this.originalTextTarget.classList.remove('hidden');
this.formTarget.classList.add('hidden');
}
_showForm() {
this.originalTextTarget.classList.add('hidden');
this.formTarget.classList.remove('hidden');
}
_submitForm() {
const formData = {
[this.data.get('model')]: {
id: this.data.get('model-id'),
[this.data.get('model-attribute')]: this.textFieldTarget.value
}
};
fetch(this.data.get('url'), {
credentials: 'same-origin',
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': Rails.csrfToken()
},
body: JSON.stringify(formData)
})
.then(response => {
if (!response.ok) {
throw response;
}
return response;
})
.then(response => response.json())
.then(json => {
this.originalTextTarget.querySelector('.inline-text-edit-target').innerText = json[this.data.get('model-attribute')];
this.clearAndHide();
})
.catch(err => {
err.json().then(err => {
this.textFieldTarget.parentElement.classList.add('error');
this.errorLabelTarget.innerText = err[this.data.get('model-attribute')];
this.errorLabelTarget.classList.remove('hidden');
});
})
}
handleKeyUp(e) {
if (e.keyCode === 13) {
this._submitForm();
}
}
}
= inline_edit_form_for(client, :name, 'ui header') do |attrib|
span.inline-text-edit-target = c[attrib]
= inline_edit_form_for(client, :website, 'sub header') do |attrib|
=< link_to c[attrib], "http://#{c[attrib]}", class: 'inline-text-edit-target'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment