Sviat Kuzhelev
Sviat Kuzhelev

Reputation: 1788

Cannot replace an elements in DOM correctly with a loop

I want to replace a div elements with class img-replace by img elements in the current DOM. But the problem is, I have only the two div element with class img-replace while the count of an img elements - three.

I have the loop that must replace an elements div by img and the condition that will stop the function if images.length > divs.length. But it does not happen and also my loop is not working here (in browser it work with random replace result).

I'll grateful for any help.

P.S. The count of div and img elements can be random, so we need the dynamic adaptive function.

function onLoad() {
  var images = document.body.getElementsByTagName('img');
  var divs = document.body.getElementsByClassName('img-replace');

  for (let i = 0; i < images.length; i++) {
    images[i].onload = function() {
      if (images.length > divs.length) return;
      divs[i].replaceWith(this);
    };

    images[i].onerror = function() {
      console.log("Error " + this.src);
      this.remove();
      return;
    };
  }
}

onLoad();
.img-replace {
  float: left;
  border: 1px solid black;
}
<div style="width:114px;height:40px;font-size:32px;letter-spacing:3px" class="img-replace">
  <span style="color:#1A53F7">G</span><span style="color:#E42131">o</span><span style="color:#FEB819">o</span><span style="color:#164AF2">g</span><span style="color:#00a315">l</span><span style="color:#E42131">e</span>
</div>

<div style="width:101px;height:40px;font-size:32px" class="img-replace">
  <span style="color:purple">Yahoo!</span>
</div>

<div style="width:100;height:40px;font-size:32px;color:#006dd4;font-weight:bold;letter-spacing: 3px; font-family:Arial">bing</div>

<hr>

<img src="https://js.cx/search/google.png" width="101" height="40" alt="Google">
<img src="http://toplogos.ru/images/logo-yahoo.jpg" width="114" height="40" alt="Yahoo">
<img src="https://js.cx/search/bing.png" width="101" height="40" alt="No file (bing)">

Upvotes: 1

Views: 81

Answers (1)

zfrisch
zfrisch

Reputation: 8660

I changed up your declarations. The reason I did so is that it is easier to iterate over anything other than an HTMLCollection which is what you return from getByClassName and getByTagName. This is because they don't have any iterable(looping) methods attached to their prototype. Instead we will use querySelectorAll which returns a NodeList, the prototype of which allows us to use the forEach method. This is useful later in the script.

Furthermore we can use Math.min to get the lowest integer between the two lengths.

      var most = Math.min(images.length, divs.length);

This changes your declarations to look like this:

  var images = document.body.querySelectorAll('img');
  var divs = document.body.querySelectorAll('.img-replace');
  var most = Math.min(images.length, divs.length);

FYI you can also lay out your declaration code like this:

  var images = document.body.querySelectorAll('img'),
  divs = document.body.querySelectorAll('.img-replace'),
  most = Math.min(images.length, divs.length);

We can then loop over the arrays until i < most because we're guaranteed to have that many images and divs.

  for (let i = 0; i < most; i++) {
    images[i].onload = function() {
    divs[i].replaceWith(this);
    };

We then loop over our images using the forEach method made available by our NodeList and add an onerror function to each image.

    images.forEach(image => image.onerror = function() {
      console.log("Error " + this.src);
      this.remove();
      return;
    });
  }
}

Note: Fat Arrows are Part of ES6 and forEach is not always implemented - per usual IE has failed to adopt the full EcmaScript Syntax in a timely fashion, so if you're looking to use this on that platform you can simply change the code to ES5:

        for ( var i = 0; i < images.length; i++ ) {
          var image = image[ i ];
          image.onerror = function() {
            console.log( "Error " + this.src );
            this.remove();
            return;
          }
        } );

function onLoad() {
  var images = document.body.querySelectorAll('img');
  var divs = document.body.querySelectorAll('.img-replace');
  var most = Math.min(images.length, divs.length);

  for (let i = 0; i < most; i++) {
    images[i].onload = function() {
    divs[i].replaceWith(this);
    };

    images.forEach(image => image.onerror = function() {
      console.log("Error " + this.src);
      this.remove();
      return;
    });
  }
}

onLoad();
.img-replace {
  float: left;
  border: 1px solid black;
}
<div style="width:114px;height:40px;font-size:32px;letter-spacing:3px" class="img-replace">
  <span style="color:#1A53F7">G</span><span style="color:#E42131">o</span><span style="color:#FEB819">o</span><span style="color:#164AF2">g</span><span style="color:#00a315">l</span><span style="color:#E42131">e</span>
</div>

<div style="width:101px;height:40px;font-size:32px" class="img-replace">
  <span style="color:purple">Yahoo!</span>
</div>

<div style="width:100;height:40px;font-size:32px;color:#006dd4;font-weight:bold;letter-spacing: 3px; font-family:Arial">bing</div>

<hr>

<img src="https://js.cx/search/google.png" width="101" height="40" alt="Google">
<img src="http://toplogos.ru/images/logo-yahoo.jpg" width="114" height="40" alt="Yahoo">
<img src="https://js.cx/search/bing.png" width="101" height="40" alt="No file (bing)">

Upvotes: 1

Related Questions