telex-wap
telex-wap

Reputation: 852

Choose <li> insertion place in list with jQuery according to id of siblings

I have a regular html ordered list:

<nav id="global_nav">
    <ol class="menu">
    <li id="Section1">Section1</li>
    <li id="Section2">Section2
    <ol>
        <li id="subsection1">Subsection1</li>
            <li id="subsection2">Subsection2</li>
           <li id="subsection3">Subsection3</li>
      </ol>
      </li>
      <li id="Section3" >Item3</li>
  </ol>
</nav>

and I made a small html form too:

<form>
    <label for="nuevo">Insert</label>
    <input type="text" id="nuevo">
    <label for="despues">After the section</label>
    <input type="text" id="despues">
    <input type="button" id="btn" value="Insert">
</form>

The point is to be able to populate the list dinamically using jQuery. For example, if in the text field 1 I type 'Section4' and in the text field 2 I type 'Section3', the function will add a new <li>element with the text 'Section4' right after the already existing 'Section3'.

I have done this, and it kind of works ok:

    $("#btn").click(function(){

    var nuevo=$('#nuevo').val();
    //var despues=$('#despues').val();
    var nl = $('<li></li>').text(nuevo).attr('id', nuevo ).slideDown();

    $(".menu").append(nl);

But as you see, I have commented out the line grabbing the value of the second text field, because I cannot understand how should I make the reference to the sibling item that will determine the placement of the new item. For instance, if the first item I attach is "Section7" and it goes appended to the very bottom of the list, how can I attach a "Section6" later on right before "Section7"?

What jQuery functions would you say that I need to use in order to get going with this? Up to now I only knew a bit of pure javascript. I am trying to understand all the cool things with jQuery but in this case I am finding in the docs a lot of functions that are apparently very similar, so I am quite confused.

Thanks!

Upvotes: 0

Views: 59

Answers (4)

Artur Filipiak
Artur Filipiak

Reputation: 9157

Your main issue has been explained in other answers.

However, I'd do it differently. I'd use select instead of input, because the user experience would be terrible when typing elements into text box like that (while it can be easily automated with select).
That way it will be much easier to use and far more accessible for the user.

SIDE NOTE:
Better make sure that the inputed id does not exist in the DOM already. You definitely don't want to have multiple elements with the same id.

function selectSet(){
    var d = $('#despues').empty();
    $('.menu li').each(function(){
        var txt = $.trim($($(this).contents()[0]).text());
        d.append('<option value="'+this.id+'">'+txt+'</option>');
    });
    // set last option as selected by default:
    $('option:last', d).prop('selected', true);
}
// set select box dynamically:
selectSet();

$("#btn").click(function(){
    var nuevo = $('#nuevo').val(),
        despues = $('#despues').val(),
        // make unique id (simple version):
        id = nuevo + ($('.menu li').length + 1);
    // hide and slideDown the new element, so that you can see the animation:
    $('<li id="'+id+'">'+nuevo+'</li>').insertAfter("#"+despues).hide().slideDown();
    // update select box:
    selectSet();
});

JSFiddle

Upvotes: 1

OddDev
OddDev

Reputation: 3734

I tried to simplify your code a little bit. Type in the following snippet a text and a section (for example "B" to append something after the list item "B"):

$("button").click(function(){
  var arr = [];
  //Store every value from each input (two values)
  $("input").each(function(){
    arr.push($(this).val());
  });
  //loop through every list item
  $("li").each(function(){
    //create a new node with the text stored in the array on the first index (0)
    var newli = document.createElement("li");
    newli.appendChild(document.createTextNode(arr[0]));
    //If the html fits the second index in the array (means the value from the second input) we append the node after that item
    ($(this).html() === arr[1]) ? $(this).append(newli) : null;
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
  <li>1</li>
  <ol>
    <li>A</li>
    <li>B</li>
  </ol>
  <li>2</li>
</ol>
<input>Text</input>
<input>Section</input>
<button>Send</button>

What we do here is creating an array to store the two input values. After that we loop through every "li" element to find the one we're searching for. If the html fits, we can append a additional node after the particular list item.

What's interesting here is the node creation. You are able to find a complete reference here: http://www.w3schools.com/js/js_htmldom_nodes.asp

Also check out this function: http://api.jquery.com/each/

Upvotes: 1

Steve Hynding
Steve Hynding

Reputation: 1859

In this line:

 $(".menu").append(nl);

You are always adding your new list item to the very end of the the whole menu.

Try this instead for inserting it after the value for "nuevo" (after uncommenting the "despues" line):

 $("#" + despues).after(nl);

For before, assume you have another text input with id "antes":

 $("#" + antes).before(nl);

In these examples, we're adding the element immediately next to (or before) the item you specified by id rather than appending it to the end of the parent element.

Upvotes: 1

Pratik
Pratik

Reputation: 1138

Here's a fiddle for the same. I hope this helps. http://jsfiddle.net/zy1f7ohc/5/

$("#btn").click(function(){

    var nuevo=$('#nuevo').val();
    var despues=$('#despues').val();

     $('<li></li>').text(nuevo).attr('id', nuevo).insertAfter("#"+despues);

 });

Upvotes: 1

Related Questions