Reputation: 19
I have the following HTML:
<ul id="data">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li>
</ul>
<br>
<div id="buttons">
<a id="edit">Click here to edit</a>
<br>
<a id="save">Click here to save</a>
</div>
I need to add an jQuery/Javascript snippet that transforms the <li>
elements into <input>
elements when the user clicks on the edit button, so he can write and change the values.
Once the process is done, with the save button the data backs to li
with the values changed.
I have this jQuery code:
$('#edit').on('click',function() {
$('#data').each(
function(){
if ($(this).find('input').length){
$(this).text($(this).find('input').val());
}
else {
var t = $(this).text();
$(this).text('').append($('<input />',{'value' : t}).val(t));
}
});
});
But my idea is to separate this in two different buttons and I can't get it to work.
How can I do that? I know it shouldn't be difficult but the truth is I don't handle jQuery/Javascript very well.
Thank you in advance.
Upvotes: 0
Views: 1425
Reputation: 65806
<li>
elements must be contained within an <ol>
or <ul>
element, so your original HTML is invalid. Also, you don't need to transform the li
into input
elements, you just need to add contenteditible
attributes to the li
elements to make them editable.
Lastly, don't use a
elements just as a click
event hook. Any item can have a click
event set up for it. <a>
elements are for navigation.
// Get reference to the list
const list = document.getElementById("data");
document.getElementById("edit").addEventListener("click", function(evt){
// Loop over the child elements
list.querySelectorAll("li").forEach(function(li){
// Make the element editable
li.setAttribute("contenteditable","true");
});
});
document.getElementById("save").addEventListener("click", function(evt){
// Loop over the child elements
list.querySelectorAll("li").forEach(function(li){
// Make the element editable
li.removeAttribute("contenteditable");
});
});
#edit, #save { color:blue; cursor:pointer; }
<ul id="data">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li>
</ul>
<br>
<div id="buttons">
<span id="edit">Click here to edit</span>
<br>
<span id="save">Click here to save</span>
</div>
Upvotes: 1
Reputation: 13840
You shouldn't need to convert the li
elements to inputs
, that needlessly complicates the process. You can just add the contenteditable
attribute. You can still add input-handling events to these, they largely function like any other text based input
element with that attribute enabled.
You can also change the button itself (both the inner text, and the function that fires when clicked in either state) instead of requiring two buttons.
var data = document.getElementById('data'),
btn = document.getElementById('edit'),
lis = data.querySelectorAll('li');
btn.addEventListener('click', function(e){
lis.forEach(function(li){
li.toggleAttribute('contenteditable');
});
if( lis[0].hasAttribute('contenteditable') ){
// Currently editing, change the button
btn.innerText = 'Click here to Save';
} else {
// We just "saved". run "save functions" here
btn.innerText = 'Click here to Edit';
}
});
[contenteditable] { outline: 1px solid #ccc; }
<ul id="data">
<li>Value 1</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li>
</ul>
<br>
<div id="buttons">
<button id="edit">Click here to Edit</button>
</div>
If you do need two buttons, you can add a second button event handler, change toggleAttribute
to addAttribute
and removeAttribute
, and remove the "inner text" changing code. But something like the above should be more than enough to get you started.
Also of note: li
elements need to be inside a list container ol
or ul
, and a
elements need an href
attribute, so I've updated both of those to more semantically appropriate ul
and button
elements, respectively.
Upvotes: 2