0

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.

5
  • 1
    Did you attempt anything? Commented Dec 22, 2020 at 21:44
  • What is your effort to try this ? Commented Dec 22, 2020 at 21:50
  • I tried something like this jsfiddle.net/davidThomas/767y4/8 and i tried to separate it in 2 different buttons but i cant get it to work correctly Commented Dec 22, 2020 at 21:56
  • 1
    <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. Commented Dec 22, 2020 at 21:58
  • Thank you. Now i have the <li> elements contained into a <ul>. So you say that it's better to use contenteditable="true/false" property with the buttons? Commented Dec 22, 2020 at 22:05

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

forEach in NodeList (querySelectorAll result), is pretty new. Support for Crome 55, Edge 16, FF 50, no IE! developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
Thanks @Sysix, it's important to note support. That said, it could easily be changed to (for var i=0, n = lis.length; i<n; i++){ lis[i].toggleAttribute('contenteditable'); } or similar, I was trying to illustrate some working code that's still relatively easy to read, not write the most globally use-case containing functionality to be copy/pasted into production lol, hence the 'enough to get you started'. IE use is ~3% in the US and ~1% worldwide, safe to say assume that OP can modify to their needs as necessary 8-)
@Sysix The ability to use Array.prototype.forEach() on the node list returned by .querySelectorAll() isn't really that new. It's been supported for a few years now in all major browsers. And, if we're still concerned with IE, you'd use Array.prototype.slice.call(nodeList).forEach(...), but honestly the use of IE at this point is really in edge cases and (finally) no longer the main stream.
1

<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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.