Search code examples
jqueryclassthiseachparent

Access This Class using Each Function


I have some code that increments each letter of a given word starting from A until reaching the destination letter. You can see the example in the code snippet below. The code works when I target a single div id but I want to make it so it will apply this incrementing text effect to every block of text with the "block" class assigned to it.

$(document).ready(function() {

  console.log("ready!");

  $('.block').each(function() {

    function Letter(table, letter, duration) {
      this.table = table;
      this.letter = letter;
      this.current = 0;
      this.delay = duration / tbl.indexOf(letter); // ms
      this.time = Date.now();
      this.done = false;
    }
    Letter.prototype.update = function() {
      if (this.done) return;
      var time = Date.now();
      if (time - this.time >= this.delay) {
        this.time = time;
        if (this.letter === this.table[this.current] || this.current === this.table.length) {
          this.done = true;
        } else {
          this.current++;
        }
      }
    };

    var word = $(this).html();
    console.log('Word: ' + word);

    var tbl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var letters = [];
    word.toUpperCase().split("").forEach(function(l) {
      letters.push(new Letter(tbl, l, 2500))
      console.log(l);
    });

    (function loop() {
      var txt = "",
        isDone = true;
      letters.forEach(function(l) {
        l.update();
        if (!l.done) isDone = false;
        txt += l.table[l.current];
      });

      // output txt
      //$("div#d").html(txt);
      $(this).parent('.block').html(txt);

      if (!isDone) requestAnimationFrame(loop);
      else { /* done */ }
    })();

  });

});

I'm trying to output the incrementing effect onto each text bit with the "block" class assigned to it:

$(this).parent('.block').html(txt);

I am trying to target each "block" class with the above line of code but it is not working. How can I do this?

Notice with this line the "Word" being incremented is whatever falls inside the "block" tag:

var word = $(this).html();

$(document).ready(function() {

  console.log("ready!");

  $('.block').each(function() {

    function Letter(table, letter, duration) {
      this.table = table;
      this.letter = letter;
      this.current = 0;
      this.delay = duration / tbl.indexOf(letter); // ms
      this.time = Date.now();
      this.done = false;
    }
    Letter.prototype.update = function() {
      if (this.done) return;
      var time = Date.now();
      if (time - this.time >= this.delay) {
        this.time = time;
        if (this.letter === this.table[this.current] ||
          this.current === this.table.length) {
          this.done = true;
        } else {
          this.current++;
        }
      }
    };

    var word = $(this).html();
    console.log('Word: ' + word);

    var tbl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var letters = [];
    word.toUpperCase().split("").forEach(function(l) {
      letters.push(new Letter(tbl, l, 2500))
      console.log(l);
    });

    (function loop() {
      var txt = "",
        isDone = true;
      letters.forEach(function(l) {
        l.update();
        if (!l.done) isDone = false;
        txt += l.table[l.current];
      });

      // output txt
      //d.innerHTML = txt;
      $("div#d").html(txt);

      if (!isDone) requestAnimationFrame(loop);
      else { /* done */ }
    })();

  });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id=d></div>

<div id="other_spans">
  <span class="block">First</span>
  <span class="block">Second</span>
  <span class="block">Third</span>


Solution

  • You can move Letter function and tbl variable outside of .each() to prevent redefining function, variable at each iteration of elements; create a reference to $(this) current element, use reference inside of loop

    $(document).ready(function() {
    
      console.log("ready!");
    
      var tbl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
      function Letter(table, letter, duration) {
        this.table = table;
        this.letter = letter;
        this.current = 0;
        this.delay = duration / tbl.indexOf(letter); // ms
        this.time = Date.now();
        this.done = false;
      }
      
      Letter.prototype.update = function() {
        if (this.done) return;
        var time = Date.now();
        if (time - this.time >= this.delay) {
          this.time = time;
          if (this.letter === this.table[this.current] 
              || this.current === this.table.length) {
            this.done = true;
          } else {
            this.current++;
          }
        }
      };
    
      $(".block").each(function() {
        // store reference to current `this` element
        var elem = $(this);
        var word = elem.html();
        console.log("Word: " + word);
        var letters = [];
    
        word.toUpperCase().split("")
        .forEach(function(l) {
          letters.push(new Letter(tbl, l, 2500))
          console.log(l);
        });
    
        (function loop() {
          var txt = "",
            isDone = true;
          letters.forEach(function(l) {
            l.update();
            if (!l.done) isDone = false;
            txt += l.table[l.current];
          });
          // `elem` : `this` element at `.each()` iteration
          elem.html(txt);
    
          if (!isDone) requestAnimationFrame(loop);
          else { /* done */ }
        })();
    
      });
    
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
    </script>
    <div id="d"></div>
    
    <div id="other_spans">
      <span class="block">First</span>
      <span class="block">Second</span>
      <span class="block">Third</span>