1

I have a table with a row defined like this:

<tr>
  <td id="to-watch">
      @Model.Results.Seats
  </td>
</tr>

Edit: The table values are being updated by ajax calls to an action which is returning data to the table in a partial

I want to log to the console when the value is greater than 2, here is the jQuery code I have:

$('#to-watch')
    .change(function () {
        if ($('#to-watch').val() > 2) {
            console.log("************ WINNER ***************");
        }
    });

I have checked in Chrome debugging tools nothing is being logged to the console when the value is greater than 2 - I rarely use jQuery / JavaScript, and after some looking, haven't been able to find the answer..

Edit: I'm making the ajax call like this:

$(document).ready(function () {

    (function loop(i) {
        setTimeout(function () {
            callAjax(i);
            //console.log("works " + i);
        },
            500); // ms
        function callAjax(i) {
            $.ajax({
                url: '/Home/StartElection',
                type: 'POST',
                data: "test",
                async: true
            })
                .done(function (partialViewResult) {
                    $("#partialTable").html(partialViewResult);
                }).always(function () {
                    if (--i) loop(i);
                });
        };
    })(650);
});
sabithpocker
  • 14,235
  • 1
  • 36
  • 69
Vinyl Warmth
  • 1,429
  • 1
  • 17
  • 34
  • 3
    You're never going to get a "change" event on a `` element unless you fire it yourself. How/why is the element content changing? – Pointy Aug 16 '16 at 12:12
  • `to-watch` is a table column. we usually use [`val()`](http://api.jquery.com/val/) for form fields. – sabithpocker Aug 16 '16 at 12:13
  • 2
    Also a `` event doesn't have a value so `.val()` won't work. You probably want `$('#to-watch').text()` – Pointy Aug 16 '16 at 12:13
  • The element is changing through ajax calls to an action returning data to the partial where the table is defined - will update my original post – Vinyl Warmth Aug 16 '16 at 12:13
  • Is it trying to compare a string value against an int? try a parseInt() on the val @VinylWarmth – Jonathan Newton Aug 16 '16 at 12:14
  • 1
    If the value is changed after an ajax call, why do you add a `change` event listener to the DOM?? Why don't you just trigger the function from the ajax call itself? – Jeremy Thille Aug 16 '16 at 12:16
  • @JeremyThille As I mentioned I rarely use JS / jQuery - please can you suggest what I should do? Thanks – Vinyl Warmth Aug 16 '16 at 12:17
  • If you have access to the AJAX `success` callback, you can try [this](http://stackoverflow.com/questions/2712124/listen-to-changes-within-a-div-and-act-accordingly) if you want to go with this pattern. Or are you already using some MVC which observes model changes? – sabithpocker Aug 16 '16 at 12:19
  • @sabithpocker please can you write out how I should do this? – Vinyl Warmth Aug 16 '16 at 12:21
  • val() is used for Get the current value of the first element in the set of matched elements.its not used for td or tr elements. please dont use .val try txt – VISHNU Radhakrishnan Aug 16 '16 at 12:22
  • Well you receive your value in your ajax callback, right? Here, just trigger your `"WINNER"`, job done. Instead of that, you use this value to update a DOM node, add an event listener to this node and wait for changes, and trigger the `"WINNER"` on change. That's overkill :) Just do `.done(function (partialViewResult) { console.log("WINNER"); })` – Jeremy Thille Aug 16 '16 at 12:29
  • If i get the problem right - you want to see changes- `@Model.Results.Seats` this code runs while rendering the page. After rendering jquery comes and it observes the element after data changes. So nothing will be changed. Either you should trigger it or change the "change" event reason. – omer faruk Aug 16 '16 at 12:35

4 Answers4

4

There are a couple of problems here.


Firstly, the change event is for input fields. It will execute the callback whenever the value of the input field changes.

There is an equivalent for when any html changes, using Mutation Observers, but it's overly complex for this scenario, as you know when the html changes, and it is done via your code.


Secondly, you are attaching an event listener to #to-watch, which I assume is nested inside #partialTable. Now we already know the change event won't work anyway, but even if this was an input field, we would have the following problem:

  1. Attach listener to DOM element with #to-watch
  2. Make ajax call
  3. On return of ajax call, replace all of #partialTable with a new version of it.
  4. The old #to-watch element is now gone, and so is it's event listener. It can't be triggered anymore.

The solution to this is called event delegation. Meaning you attach the listener to a parent element that doesn't change, and it checks if any child elements matching the selector are changed. This means that id the child elements were changed dynamically, the listener will still work.


Then there are also the aforementioned:

$('...').text() will give you the contents of any DOM element, where as $('...').val() will give the value of an input field

JQUERY .text() docs

JQUERY .val() docs

You want to do a numerical comparison (X > Y), so you should convert the string "2" which is the text of $('#to-watch') into an integer with parseInt(x)


The solution to your problem

When you update the #partialTable, you know that the #to-watch element has received a new value, so now is the time to check it:

      function callAjax(i) {
        $.ajax({
            url: '/Home/StartElection',
            type: 'POST',
            data: "test",
            async: true
        }).done(function (partialViewResult) {
            $("#partialTable").html(partialViewResult);
            if (parseInt($('#to-watch').text()) > 2) {
              console.log("************ WINNER ***************");
            }
        }).always(function () {
            if (--i) loop(i);
        });
    };
Community
  • 1
  • 1
caffeinated.tech
  • 5,846
  • 19
  • 36
  • 1
    Thank you!! Why indeed update the view, then trigger a function when the view has changed? This is absolute overkill. Just trigger what you want in the ajax call. +1 – Jeremy Thille Aug 16 '16 at 12:43
0

Instead of val() can you please try text() in the JQuery function.

anujjain0801
  • 102
  • 3
  • not sure why this has been downvoted? this seems like the correct solution – Ash Aug 16 '16 at 12:21
  • @Ash Because while `text()` is a step in the right direction, you're then comparing a string to an integer in `2`. It would always return false. – Drew Kennedy Aug 16 '16 at 12:44
0

Please try text() .

text() - Sets or returns the text content of selected elements
html() - Sets or returns the content of selected elements (including HTML markup)
val() - Sets or returns the value of form fields

Please check the this link for DOM Insertion using Jquery

0
$(body).on('mycontentchange','#to-watch', function() {//make sure #to-watch is available in DOM while binding, or use `on` to delegate the event
    console.log('new content updated',$('#to-watch').text());
});

            .done(function (partialViewResult) {
                $("#partialTable").html(partialViewResult);
                $('#to-watch').trigger('mycontentchange');
            }).always(function () {
                if (--i) loop(i);
            });

This is just a direct answer to the question, you probably have better ways to solve the problem :) This is an overkill as @jeremy pointed out considering your continuous polling.

sabithpocker
  • 14,235
  • 1
  • 36
  • 69
  • This can't work. You're rewriting the entire table with brand new content, then you're triggering a "change" event on stuff that's just been added to the dom. – Jeremy Thille Aug 16 '16 at 12:33
  • I have suggested event delegation using `on`, updating that now :) Thank you for pointing that out – sabithpocker Aug 16 '16 at 12:34