Reputation: 693
I am looking for a simple way to implement inline editing in a table (with Django). I did not test stuff like Django-Front or django-inlineedit so far. I already found out, that not all simple solutions work for me. jqInlineEdit and inline-edit.jquery.js do work only with unique selectors, as I described here.
With jQuery.editable (jquery.inline-edit.js), I do not have these problems, but I do not know how to get the id and save the data.
<div id="remark4" class="editable" data-cid="4">Test #4</div>
<div id="remark5" class="editable" data-cid="5">Test #5</div>
<div id="remark6" class="editable" data-cid="6">Test #6</div>
<script src="file:jquery.inline-edit.js"></script>
<script>
$('.remark').inlineEdit('click', {
// use textarea instead of input field
type: 'textarea',
// attributes for input field or textarea
attributes: {
id: $(this).attr("data-cid"),
class: 'input-class-1 input-class-2 input-class-3',
style: 'background:#ffe;'
}
});
</script>
Is the $(this).attr("data-cid")
part correct? How can I run a let's say alert(c_id + content)
after the content in the form has changed? I did not found a documentation or an example for that and trial and error was not successful so far.
Followup:
The docu does give examples. Incredible that I did not see this earlier, sorry for that.
I tried the following code instead of the one above:
var option = { trigger: $(".editable"), action: "click" };
$(".editable").editable(option, function (e) {
alert(e.value);
});
This is the error message: TypeError: $(...).editable is not a function
What's still wrong?
Upvotes: 2
Views: 4704
Reputation: 206347
If I may suggest an alternative using HTMLElement.contentEditable API.
$("[data-cid]").prop({tabindex: 1, contenteditable: true}).on({
focusin() {
this.__html = $(this).html(); // Store current HTML content
},
focusout() {
const data = {
cid: this.dataset.cid,
html: this.innerHTML,
};
if (this.__html === data.html) return; // Nothing has changed.
console.log(data); // Something changed, send data to server.
}
})
<div data-cid="4">Test #4</div>
<div data-cid="5">Test #5</div>
<div data-cid="6">Test #6</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
Here's an example how you can simply create your own reusable function:
// Editable
function Editable(sel, options) {
if (!(this instanceof Editable)) return new Editable(...arguments);
const attr = (EL, obj) => Object.entries(obj).forEach(([prop, val]) => EL.setAttribute(prop, val));
Object.assign(this, {
onStart() {},
onInput() {},
onEnd() {},
classEditing: "is-editing", // added onStart
classModified: "is-modified", // added onEnd if content changed
}, options || {}, {
elements: document.querySelectorAll(sel),
element: null, // the latest edited Element
isModified: false, // true if onEnd the HTML content has changed
});
const start = (ev) => {
this.isModified = false;
this.element = ev.currentTarget;
this.element.classList.add(this.classEditing);
this.text_before = ev.currentTarget.textContent;
this.html_before = ev.currentTarget.innerHTML;
this.onStart.call(this.element, ev, this);
};
const input = (ev) => {
this.text = this.element.textContent;
this.html = this.element.innerHTML;
this.isModified = this.html !== this.html_before;
this.element.classList.toggle(this.classModified, this.isModified);
this.onInput.call(this.element, ev, this);
}
const end = (ev) => {
this.element.classList.remove(this.classEditing);
this.onEnd.call(this.element, ev, this);
}
this.elements.forEach(el => {
attr(el, {tabindex: 1, contenteditable: true});
el.addEventListener("focusin", start);
el.addEventListener("input", input);
el.addEventListener("focusout", end);
});
return this;
}
// Use like:
Editable(".editable", {
onEnd(ev, UI) { // ev=Event UI=Editable this=HTMLElement
if (!UI.isModified) return; // No change in content. Abort here.
const data = {
cid: this.dataset.cid,
text: this.textContent, // or you can also use UI.text
}
console.log(data); // Submit your data to server
}
});
/* Your styles */
.editable {
padding: 10px;
background: #eee;
display: inline-block;
}
/* this class is handled by Editable */
.is-modified {
background: #bff;
}
/* this class is handled by Editable */
.is-editing {
background: #bfb;
outline: none;
}
<div class="editable" data-cid="4">Test #4</div>
<div class="editable" data-cid="5">Test #5</div>
<div class="editable" data-cid="6">Test #6</div>
<div class="editable" data-cid="7">Test #7</div>
Editable("selector", options);
Returns: the Editable instance
Properties:
classEditing:
String - Class to be added on focusin (Default:"is-editing"
)
classModified:
String - Class to be added on focusout if content has changed (Default:"is-modified"
)Methods:
onStart(event, UI)
Function - Triggers on"focusin"
Event
Param:event
the Event that triggered the callback
Param:UI
the Editable instance Object
Bind:this
is bound to the associated HTMLElement
onInput(event, UI)
Function - Triggers on"input"
Event
Param:event
the Event that triggered the callback
Param:UI
the Editable instance Object
Bind:this
is bound to the associated HTMLElement
onEnd(event, UI)
Function - Triggers on"focusout"
Event
Param:event
the Event that triggered the callback
Param:UI
the Editable instance Object
Bind:this
is bound to the associated HTMLElementParam
UI
(Editable instance) properties:
text
String - The currently edited element's textContent
html
String - The currently edited element's innerHTML
text_before
String - The element's textContent before the edit
html_before
String - The element's innerHTML before the edit
isModified
Boolean -true
if innerHTML is not equal to the original
elements
- static (not live) NodeList of Elements
element
- The latest edited HTMLElement
Upvotes: 10