LaVOZs

The World’s Largest Online Community for Developers

'; javascript - When using appendChild, the justify property is invalid - LavOzs.Com

At work, I need to delete the elements in a container and then add them back again. I found that the text-align: justify attribute is valid before I delete the elements, but invalid when I add the elements back in.

Here is the full code:

<html>
  <head>
  </head>
  <style>
    .container{
      width: 660px;
      text-align: justify;
      border: solid 1px #999;
    }
    .container:after{
      content: '';
      display: inline-block;
      width: 100%;
      height: 0;
    }
    .item{
      display: inline-block;
      width: 300px;
      height: 100px;
      border: solid 1px red;
    }
    .itemImg{
      width: 100%;
      height: 100%;
    }
  </style>
  <body>
    <div id="container" class="container">
      <a class="item" href="" > <img class="itemImg" src="https://uidesign.gbtcdn.com/GB/image/mobile/20190221_7802/ru400x240aa.jpg?impolicy=high" > </a>
      <a class="item" href="" > <img class="itemImg" src="https://uidesign.gbtcdn.com/GB/image/mobile/20190221_7802/ru400x240aa.jpg?impolicy=high" > </a>
    </div>
  </body>
  <script type="text/javascript">
    function init(){
      const domParent = document.querySelector('#container');
      const fragment = document.createDocumentFragment();

      // save old elements
      const orderDomObj = [];
      const oldDoms = document.querySelectorAll('.item', domParent);
      oldDoms.forEach((item) => {
        orderDomObj.push(item)
      })
      // add new elements
      domParent.innerHTML = '';
      orderDomObj.forEach((value) => {
        fragment.appendChild(value);
      });
      domParent.appendChild(fragment)
    }

    window.onload = init

  </script>
</html>

I have found that in this section:

oldDoms.forEach((item) => {
    orderDomObj.push(item);
});

If I push the items into orderDomObj using template literals like so:

oldDoms.forEach((item) => {
     orderDomObj.push(`
         ${item}
     `);
});

Then the text-align: justify; CSS declaration works correctly.

Why does the template literal version work correctly, but the push version not work correctly?

Edited Answer

Now that you have figured out a workaround, I think I know how it works.

The key portion is here:

orderDomObj.push(`
          ${item.outerHTML}  
        `)

You are using template literals in this section, and the newline character is creating a text node between the <a> tags. This mimics what is in the #container before you remove the elements, which you can verify in the console (this is your page without the JS running):

Text Nodes

So, in the original, you copy over the Element nodes, but not the text nodes in between them. Then, when you add everything back to the DOM, there are no text nodes between the elements, so the justify doesn't work.

You don't even need the document fragment, this script works just as well:

function init(){
  const domParent = document.querySelector('#container');

  // save old elements
  const orderDomObj = [];
  const oldDoms = document.querySelectorAll('.item', domParent);
  oldDoms.forEach((item) => {
    orderDomObj.push(item)
    orderDomObj.push(document.createTextNode('\n'));
  })
  // add new elements
  domParent.innerHTML = '';
  orderDomObj.forEach((value) => {
    domParent.appendChild(value);
  });
}

Here's a gif of editing the HTML to add in newline characters to mimic what's happening:Demo

But honestly, this does the same thing:

function init(){
  const domParent = document.querySelector('#container');
  const oldContainer = domParent.innerHTML;
  domParent.innerHTML = '';
  domParent.innerHTML = oldContainer;
}

I'm not sure why you are wiping the DOM then repopulating with the same content, but there seems to be many ways to go about that.

I modified the init function as follows, and it worked. But I still want to know why the code in the question did not work:

function init(){
  const domParent = document.querySelector('#container');
  const fragment = document.createDocumentFragment();

  // save old elements
  const orderDomObj = [];
  const oldDoms = document.querySelectorAll('.item', domParent);
  oldDoms.forEach((item) => {
    // no
    // orderDomObj.push(item.outerHTML)
    // yes
    orderDomObj.push(`
      ${item.outerHTML}  
    `)
  })
  // add new elements
  domParent.innerHTML = '';
  orderDomObj.forEach((value) => {
    fragment.appendChild(document.createRange().createContextualFragment(value));
  });
  domParent.appendChild(fragment)
}

I made some attempts and found that justify does not take effect when there is no whitespace between the elements. As shown in the following figure, element 1 and element 2 are abnormal, while element 3 and element 4 are normal. enter image description here

code show as below:

<html>
    <head>
      </head>
      <style>
        .container{
          width: 660px;
          border: solid 1px #999;
          text-align: justify;
          padding: 0;
        }
        .container:after{
          content: '';
          display: inline-block;
          width: 100%;
          height: 0;
        }
        a{
          display: inline-block;
          width: 300px;
          height: 100px;
          border: solid 1px red;
        }
      </style>
      <body>
        <div class="container">
          <a> 1
          </a><a
          >2</a>
          <a>3</a>
          <a>4</a>
        </div>
      </body>
    </html>

When using appendchild to add elements, there is no whitespace between the elements.

Related
Detecting an undefined object property
How do I check if an object has a specific property in JavaScript?
How can I merge properties of two JavaScript objects dynamically?
How do I remove a property from a JavaScript object?
When to use double or single quotes in JavaScript?
Sorting an array of objects by property values
Sort array of objects by string property value
Detecting an “invalid date” Date instance in JavaScript
How to decide when to use Node.js?
Iterate through object properties