0

I've been trying to detect if a spans content has changed and if it has changed to get the value, I've made a code snippet below that will change the span content for testing yet for some reason I can't detect whether the content has changed. I think it's possibly a limitation of the "changed" jquery where you possibly have to declare the change it can expect for it to do anything.

Does anyone have any recommendations of a better way to execute this? Once I have the changed value in js I'll need to do js math on it to finish the solution.

$(document).ready(function() {

  // change contents of a span - testing purposes

  var delay = (function() {
    var timer = 0;
    return function(callback, ms) {
      clearTimeout(timer);
      timer = setTimeout(callback, ms);
    };
  })();

  delay(function() {
    document.getElementById('price').innerHTML = '$100.00';
  }, 5000);

  // detect a change to contents a span

  $(".price").change(function() {
    alert(this.value);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<span class="price">$90.00</span>
Liam
  • 27,717
  • 28
  • 128
  • 190
Josh
  • 3
  • 2

3 Answers3

1

Many issues

  1. Spans do not have values
  2. you have a class, not an ID so the selector is .price in a jQuery statement or document.querySelector(".price") or document.querySelectorAll(".price") in DOM
  3. Only form elements like <input>, <textarea> and <select> elements have a change event
  4. What changes the span? Why can't you just add code to where you change the span?
  5. If not, then you need a mutation observer:

$(function() {

  // change contents of a span - testing purposes

  const delay = (() => { let timer = 0; return (callback, ms) => { clearTimeout(timer); timer = setTimeout(callback, ms); }; })();
  delay(() => { $('.price').html('$100.00'); }, 2000);

  // detect a change to contents a span

  const elementToObserve = $('.price')[0]; // get the DOM element
  
  const process = () => { // callback
    const text = elementToObserve.textContent ; // gets $100.00
    const amount = +text.trim().slice(1); // converts to 100
    console.log("changed to", amount)
  }
  

  // create a new instance of 'MutationObserver' named 'observer', 
  // passing it a callback function
  const observer = new MutationObserver(process);

  // call 'observe' on that MutationObserver instance, 
  // passing it the element to observe, and the options object
  observer.observe(elementToObserve, { childList: true });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<span class="price">$90.00</span>

Older version 'DOMSubtreeModified' - note it triggers twice!

$(function() {

  // change contents of a span - testing purposes

  const delay = (() => { let timer = 0; return (callback, ms) => { clearTimeout(timer); timer = setTimeout(callback, ms); }; })();
  delay(() => { $('.price').html('$100.00'); }, 2000);

  // detect a change to contents a span - deprecated but short

  $(".price").on("DOMSubtreeModified", function(e) {
    const amount = +$(this).text().trim().slice(1); // converts to 100
    console.log(new Date(),amount)
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<span class="price">$90.00</span>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • 1
    This is brilliant - I noticed other methods using a depreciated method and I'm sure a lot of people will find this really useful. Thanks for the help! – Josh Apr 25 '22 at 14:05
  • I cleaned the answer a little to get rid on some unnecessary code – mplungjan Apr 25 '22 at 14:34
  • 1
    Thanks! - I'll update mine with the trimmed code, by the way this worked perfectly with the math equation and updating secondary spans. – Josh Apr 25 '22 at 14:55
0

Use MutationObserver

$(document).ready(function() {
    var delay = (function() {
    var timer = 0;
    return function(callback, ms) {
        clearTimeout(timer);
        timer = setTimeout(callback, ms);
      };
    })();

    delay(function() {
      document.getElementById('price').innerHTML = '$100.00';
    }, 5000);

    // Select the target node.
    var target = document.querySelector('#price')

    // Create an observer instance.
    var observer = new MutationObserver(function(mutations) {
        console.log(target.innerText);   
    });

    // Pass in the target node, as well as the observer options.
    observer.observe(target, {
        attributes:    true,
        childList:     true,
        characterData: true
    });

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

<span id="price">$90.00</span>
Sahil Thummar
  • 1,926
  • 16
  • 16
-1

If you really need to run some code when the span content is changed you can try Mutation observer https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#example

Ayoub
  • 46
  • 1
  • 2