Home > other >  Multiple Word Counters For Multiple Divs
Multiple Word Counters For Multiple Divs

Time:05-11

For my wordlist website I'm trying to make a automatic word counter for every list. I'm able to count the words of one list but when I add more the counter counts all the lists. I can't find a solution anywhere so all help is greatly appreciated.

JSFiddle link: http://jsfiddle.net/ge7akmzj/

$(function() {
    var text = $('.input').text();
    var wordsCount = text.split(',').length;
    $('.output').html('word count:'   wordsCount);
});
<span >
  These, are, 7, words, as, a, demonstration
</span>
<br>
<br>
<span class='output'></span>
<br>
<br>
<span >
  These, are, 7, words, as, a, demonstration
</span>
<br>
<br>
<span class='output'></span>

<script type = "text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

CodePudding user response:

$(function() {
  $(".input").each(function(element) {
    var text = $(this).text();
    var wordsCount = text.split(',').length;
    $(this).parent().find('.output').html('word count:'   wordsCount);
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <span >
    These, are, 7, words, as, a, demonstrationd, demonstrationd,12,13,15,15
    </span>
  <br>
  <br>
    <span class='output'>
    </span>
</div>
<div >
  <span >
  These, are, 7, words, as, a, demonstration,
  </span>
  <br>
  <br>
  <span class='output'>
  </span>
</div>

CodePudding user response:

$(function() {
    // iterate over the input DOM element
    $('.input').each(function (index) {
        const text = $(this).text()
        const wordsCount = text.split(',').length
        // select the corresponding output DOM element and update the text
        $('.output').eq(index).text('word count:'   wordsCount);
    });
});

CodePudding user response:

You need to use .each to loop through each element

$(function() {
  $(".input").each(function(element) {
    var text = $(this).text();
    var wordsCount = text.split(',').length;
    $(this).parent().find('.output').html('word count:'   wordsCount);
    });
});
<div>
  <span >
    These, are, 7, words, as, a, demonstration
  </span>
  <br>
  <br>
  <span class='output'></span>
  <br>
  <br>
</div>
<div>
  <span >
    These, are, 4, words
  </span>
  <br>
  <br>
  <span class='output'></span>
</div>
<script type = "text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

CodePudding user response:

While you've already accepted an answer, I thought I'd take the opportunity to show you an alternative approach, and reinforce the fact that – while you certainly have to iterate over the various elements – you don't need to use each() to do so.

Also, I opted to show a plain JavaScript approach to solving the exact same problem in order to demonstrate that although jQuery offers some syntactic sugar, and abstracts away some of the verbose aspects of JavaScript, JavaScript has, itself, adopted some of jQuery's approach, and methods.

That said, the explanation of the code is in the comments to that code, below:

// defining a named function, using Arrow syntax, passing
// the Event Object - passed automatically from the (later)
// use of EventTarget.addEventListener() - to the body of
// the function:
const wordCount_JS = (evt) => {
  // retrieving the element to which the function was bound
  // (evt.currentTarget, the <button>) and then using
  // Element.closest() to navigate to the closest ancestor
  // <section> element:
  let section = evt.currentTarget.closest('section'),
    // from that <section> we use Element.querySelectorAll()
    // to find all elements with a class of 'input':
    wordSources = section.querySelectorAll('.input');

  // we use NodeList.prototype.forEach(), along with its
  // anonymous function, to iterate over the NodeList of
  // elements:
  wordSources.forEach(
    // passing a reference to the current Node of the NodeList
    // over which we're iterating:
    (text) => {
      // taking the text-content of the current Node:
      let count = text.textContent
        // splitting it on the ',' character:
        .split(',')
        // and finding the length of that Array of strings:
        .length;

      // here find the next element-sibling of the current
      // 'text' Node, and set its text-content to the
      // number held in the 'count' variable:
      text.nextElementSibling.textContent = count;
    })
};

// here we use document.querySelector() to find the first of any
// element in the document that matches the CSS selector, and then
// use EventTarget.addEventListener() to bind the wordCount_JS()
// function (note the deliberate lack of parentheses) as the event-
// handler for the 'click' event:
document.querySelector('.JavaScript button').addEventListener('click', wordCount_JS);

// here we use jQuery, first to select the <button> element(s) held
// within any .jQuery element(s), and then use the on() method to
// bind the anonymous function of that method as the event-handler
// for the 'click' event:
$('.jQuery button').on('click', function() {
  // from the clicked <button> element(s) we navigate to the
  // closest ancestor <section> element:
  $(this).closest('section')
    // and from that element we find all elements with a class of
    // 'output':
    .find('.output')
    // and use the text() method, with its anonymous function:
    .text(function() {
      // to iterate over all elements to which the method was
      // chained.
      // here, we take $(this) the current '.output' element:
      return $(this)
        // find its previous sibling, if it matches the
        // supplied selector:
        .prev('.input')
        // retrieve the text-content of that element:
        .text()
        // split that string of text on the ',' character:
        .split(',')
        // and retrieve the number of elements in the
        // resulting Array of Strings; this is then -
        // thanks to the 'return' - returned to the
        // text() method chained to the '.output' elements:
        .length;
  });
});
/* a simple means of normalising the layout of the document to reduce
   cross-browser differences, as well as different default layout and
   sizing of various elements within the same browser: */
*,
 ::before,
 ::after {
  box-sizing: border-box;
  font-family: Roboto, Montserrat, system-ui;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.4;
  margin: 0;
  padding: 0;
}

section {
  border: 0.1em solid currentColor;
  color: #363;
  display: grid;
  /* setting a gap between adjacent elements, whether
     vertically, or horizontally, adjacent: */
  gap: 0.5em;
  /* using CSS Logical properties, margin-block is the
     sets both the top (margin-block-start)
     and bottom (margin-block-end) margin in English
     (left-to-right, top-to-bottom) language: */
  margin-block: 1em;
  /* margin-inline sets the left (margin-inline-start)
     and right (margin-inline-end) margins in a 
     left-to-right language, such as English: */
  margin-inline: auto;
  /* again, using logical properties: */
  padding-block: 0.25em;
  padding-inline: 0.5em;
  /* defining the width as 70vw, with a minimum
     possible width of 25em and a maximum width
     of 700px: */
  width: clamp(25em, 70vw, 700px);
}

/* using CSS generated content to prepend the
   (presentational) information, concatenating
   the attribute-value of the 'class' attribute
   between the 'Using ' and ': ' strings: */
section::before {
  content: "Using " attr(class) ": ";
  /* logical properties, setting only the final
     border of the block axis: */
  border-block-end: 0.1em solid currentColor;
}

/* assigning a border to the edge of the element
   along its block-end border (the bottom border
   in English): */
.output {
  border-block-end: 0.1em solid currentColor;
}

.output:not(:last-of-type) {
  /* adding a margin of 0.5em following the end
     boundary of the .output element(s) which
     are not the :last-of-type (so not the last
     of its element-type (<span>) within this
     parent): */
  margin-block-end: 0.5em;
}

/* showing the "Word count: " string before the
   content of all elements with a class of
   'output': */
.output::before {
  color: #9a9;
  content: "Word count: ";
}

/* for those elements with a class of 'output'
   which are not empty (so which do not contain
   any child-elements, or text-nodes: */
.output:empty::before {
  content: "No count as yet.";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- I removed all <br> elements, and used CSS for layout and spacing; other
     than that I didn't really change the HTML other than varying the text a
     little, duping the content and wrapping it in a parent <section>: -->
<section >
  <span >These, are, 7, words, as, a, demonstration</span>
  <span class='output'></span>
  <span >An, entirely, unplanned, and, typed, in, a, stream-of-consciousness, manner, string, of, sundry, words.</span>
  <span class='output'></span>
  <span >Lorem, ipsum, dolor, sit, amet, consectetur, adipisicing, elit. Sequi, laboriosam, eius, magni, vitae, sit, velit, alias, ab, iusto, amet, similique, mollitia, magnam, quod, laudantium, facere, tempora, fugit, recusandae, adipisci, quaerat.</span>
  <span ></span>
  <button type="button">Show word count</button>
</section>

<section >
  <span >These, are, 7, words, as, a, demonstration</span>
  <span class='output'></span>
  <span >An, entirely, unplanned, and, typed, in, a, stream-of-consciousness, manner, string, of, sundry, words.</span>
  <span class='output'></span>
  <span >Lorem, ipsum, dolor, sit, amet, consectetur, adipisicing, elit. Sequi, laboriosam, eius, magni, vitae, sit, velit, alias, ab, iusto, amet, similique, mollitia, magnam, quod, laudantium, facere, tempora, fugit, recusandae, adipisci, quaerat.</span>
  <span ></span>
  <button type="button">Show word count</button>
</section>

JS Fiddle demo.

References:

  • Related