Despite putting it in "Document Ready", why can I see jQuery 'append' happening when I load the page?

Viewed 33

I have code that moves around divs. It's supposed to happen out of the user's view. But whenever I clear my cache and refresh the page to test it, I see these divs moving around every time! It's super annoying visually...

I have 2 ways of doing it, and both I can see visually occur.

1st way:

    //START MOVE
    [...document.querySelectorAll('#primary')].forEach(x => {
      moveElement(
        x.querySelector('.snax-voting-container-body'),
        x.querySelector('.object1')
        //x.querySelector('.snax-voting-container-body')
      );
    });

    /**
     * Moves an element by detaching it from its parent and appending it to
     * a target.
     * @param {HTMLElement|String} ref - Element to detach and move
     * @param {HTMLElement|String} target - Element where ref will be appended
     * @return Returns the element that was moved
     */
    function moveElement(ref, target) {
      if (typeof target === 'string') target = document.querySelector(target);
      target.appendChild(detatchElement(ref));
      return ref;
    }

    /**
     * Detaches an element from its parent.
     * @param {HTMLElement|String} ref - Element to detach from its parent
     * @return Returns the detached element
     */
    function detatchElement(ref) {
      if (typeof ref === 'string') ref = document.querySelector(ref);
      return ref.parentElement.removeChild(ref);
    }//end of MOVE

Second way:

    $('.object1').append(  $('.snax-voting-container-body') );

Any ideas why this is happening-- why I can actually see this process despite having it in $(document).ready(function () {? Thanks.

1 Answers

Problem

$(document).ready() will wait for the DOM to render before executing your moves, so you'll see the old position momentarily before it make the change. This is a limitation because you're using JavaScript to manipulate the DOM after its been rendered (and you need to wait till after it's been rendered otherwise theres nothing to move).

Solution

A potential work around could be to hide the elements you are going to move and then only reveal once the move has been completed.

You could achieve this by adding a .hidden class to the elements to be moved and then remove that class after the move.

var ref = document.querySelector('.foo'); // Element to move
var target = document.querySelector('.red') // Destination

moveElement(ref, target); // Move
ref.classList.remove('hide') // Unhide

function detatchElement(ref) {
  if (typeof ref === 'string') ref = document.querySelector(ref);
  return ref.parentElement.removeChild(ref);
}
    
function moveElement(ref, target) {
  if (typeof target === 'string') target = document.querySelector(target);
  target.appendChild(detatchElement(ref));
  return ref;
}
div {
  display: grid;
  place-items: center;
  height: 100px;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}

.foo {
  color: white;
  font-size: 20px;
}

.hide {
  display: none;
}
<div class="red"></div>
<div class="blue"><span class="foo hide">I started in blue.</span></div>

Related