javascriptdomdom-manipulation

Wrap multiple elements in new div without destroying them - Javascript DOM manipulation


I am trying to 'de-jquery' some code.

I have a div like so:

<div id="main">
    <div class="blue"></div>
    <div class="green"></div>
    <div class="yellow"></div>
</div>

And I wish to insert a wrapper div around all elements except the first. The full number of elements is undetermined, there could be more.

The current solution uses jquery nextAll and wrapAll to produce the following result:

HTML

<div id="main">
    <div class="blue"></div>
    <div class="wrapper">
        <div class="green"></div>
        <div class="yellow"></div>
    </div>
</div>

jQuery

$(".blue").each(function() {
        $(this)
          .nextAll()
          .wrapAll('<div class="wrapper"></div>');
    });

How can I remove all jQuery from this and make it vanilla?

I cannot see any wrap type methods. I could grab the HTML that doesn't have index of [0] and insert it into a new div, then insert that after .blue but that seems messy. Is there a better way?


Solution

  • edit: oh you just want to skip the first item…

    skip this solution to the new solution at the bottom.

    // this is how you can grab a node.
    // alternatively you could use document.querySelectorAll
    // (wich will be similar to how $() works)
    const blue = document.querySelector('.blue');
    
    // if you desire to use querySelectorAll you can have something similar to
    // .each() like: [...document.querySelectorAll('.blue')].map(element => {});
    
    // this is not a necessity but keeps code a little more organized,
    // instead of throwing this into line 22.
    const nodes = [];
    let element = blue;
    while(element = element.nextElementSibling) {
      nodes.push(element);
    }
    
    // let's create a new div
    const wrapper = document.createElement('div');
    // and add the classname of your desire.
    wrapper.classList.add('wrapper');
    // now let's append all nodes:
    wrapper.append(...nodes);
    
    // and append the wrapper to the .main div:
    blue.parentNode.appendChild(wrapper);
    
    // and for the fun of it, let's display the outcome:
    document.body.appendChild(document.createElement('code')).textContent = blue.parentNode.outerHTML;
    div {
      padding: 2px;
      border: 1px dotted #000;
      min-height: 20px;
      box-sizing: border-box;
      position: relative;
    }
    <div id="main">
        <div class="blue"></div>
        <div class="green"></div>
        <div class="yellow"></div>
    </div>


    i just realized you just want to iterate after the first child…

    let's try this then:

    // let's grab the main element:
    const main = document.querySelector('#main');
    // you could also do this: document.querySelector('.blue').parentNode;
    
    // now let's grab the children of that node and strip the first one:
    const nodes = [...main.children].splice(1);
    
    // now let's create the wrapper div
    const wrapper = document.createElement('div');
    wrapper.classList.add('wrapper');
    
    // and append all children:
    wrapper.append(...nodes);
    
    // and ofc add the wrapper to the container:
    main.appendChild(wrapper);
    div {
      padding: 2px;
      border: 1px dotted #000;
      min-height: 20px;
      box-sizing: border-box;
      position: relative;
    }
    <div id="main">
        <div class="blue"></div>
        <div class="green"></div>
        <div class="yellow"></div>
    </div>