views:

44

answers:

2

I'm trying to hide tr's within a html table if the inputs inside them match a certain criteria. The criteria is defined by a dropdown's selected value. I'm doing it like so:

$(function () {

  $('body').find('#p_Selection').live('change', function () {

    var type = $('body').find('#p_Selection').attr('value');
    var tableRow = $('.goods').find('.detail-child tr');

    tableRow.each(function (index) {

      var Record_LidExpected = $('input[id$=Record[' + index + ']_LidExpected]').attr('value');
      var Record_LidObtained = $('input[id$=Record[' + index + ']_LidObtained]').attr('value');
      var Record_QuantityExpected = $('input[id$=Record[' + index + ']_QuantityExpected]').attr('value');
      var Record_QuantityObtained = $('input[id$=Record[' + index + ']_QuantityObtained]').attr('value');

      if (type == "1") {

        if (Record_LidExpected != Record_LidObtained) {
          $(this).hide();
        }
        else {
          if (Record_QuantityExpected != Record_QuantityObtained) {
            $(this).hide();
          }
        }
      }
      else {
        if (type == "2") {
          if (Record_LidExpected == Record_LidObtained) {
            $(this).hide();
          }
          else {
            if (Record_QuantityExpected == Record_QuantityObtained) {
              $(this).hide();
            }
          }
        }
        else {
          if (type == "0") {
            $(this).show();
          }
        }
      }
    });
  });
});​

This script became extremely slow inside my aspx page and it just won't complete because it is too heavy. Any suggestions on how to make it faster?

A: 

In my rewrite you'll notice a few things.

  1. I ommitted $('body').find() because it doesn't give you any advantage over selecting #p_Selection directly.
  2. When selecting the input values using the $() function, I am adding this as a second argument. This basically tells jQuery to look for the input within this (which in this case refers to the current tr in the each loop. The advantage here is that jQuery doesn't need to search the entire DOM for that particular input, just within the current tr tag.
  3. I just cleaned up your if/else logic a bit using a switch statement and some || operators.

I think that this should run faster now.

<script type="text/javascript">
  $(function() {

    $('#p_Selection').live('change', function() {
      var type = $(this).val();

      var Record_LidExpected, 
          Record_LidObtained, 
          Record_QuantityExpected, 
          Record_QuantityObtained;

      $('.goods .detail-child tr').each(function(index) {

        Record_LidExpected = $('input[id$=Record['+index+']_LidExpected]', this).val();
        Record_LidObtained = $('input[id$=Record[' + index + ']_LidObtained]', this).val();
        Record_QuantityExpected = $('input[id$=Record[' + index + ']_QuantityExpected]', this).val();
        Record_QuantityObtained = $('input[id$=Record[' + index + ']_QuantityObtained]', this).val();

        switch(type) {
          case "1" :
            if (Record_LidExpected != Record_LidObtained || Record_QuantityExpected != Record_QuantityObtained) {
              $(this).hide();
            }
          break;
          case "2" :
            if (Record_LidExpected == Record_LidObtained || Record_QuantityExpected == Record_QuantityObtained) {
              $(this).hide();
            }
          break;

          case "0":
            $(this).show();
          break;
        }
      });
    });
  });
</script>
jessegavin
I liked everyone's suggestions and they're great for my learning of jQuery but unfortunately I can only mark one reply as the answer and Jesse's was the most helpful. Thanks to everyone for helping me out.
Hallaghan
but it still does **too many things in one `onchange` event**. consider my suggestions in my answer
galambalazs
@galambalazs "too many things"? What do you mean by that?
jessegavin
`$('.goods .detail-child tr')` will run on every `onchange` event, your input selectors are **vastly inefficient**, and with `$(this)` you also make a new instance of the jQuery object every time a change happens. Finally, as a side note, putting the variables outside of the function will eventually make the code slower, because making variables are cheap, but if they are up in the scope chain they will have slower access time.
galambalazs
+1. Thanks for a detailed explanation.
jessegavin
:) after the response from the OP I'm almost sure the problem will be jQuery itself, because it adds too much overhead to the operations. This is the cost of short and simple code.
galambalazs
+1  A: 

The key points of preformance optimization

  • do few selects (don't select everything onchange)
  • save selections that won't change
  • be as specific as possible when you select elements

Bonus: learn to use else if because your branches become clearer.

Here is the code:

$(function () {

  // pre-select things that won't change
  var $sel = $('#p_Selection'); 
  var tableRow = $('.goods .detail-child tr');

  //
  // ONCHANGE EVENT 
  // keep in mind that everything in it will be very costly
  //
  $sel.live('change', function () {

    var type = $sel.attr('value');

    tableRow.each(function (index) {

      // this just makes the code shorter
      var record = '#Record'+index;

      // simple ID selector is enough, since its unique
      var Record_LidExpected =  $(record+'_LidExpected').attr('value');
      var Record_LidObtained =  $(record+'_LidObtained').attr('value');
      var Record_QuantityExpected = $(record+'_QuantityExpected').attr('value');
      var Record_QuantityObtained = $(record+'_QuantityObtained').attr('value');

      if (type == "1") {
        if (Record_LidExpected != Record_LidObtained) {
          $(this).hide();
        } else if (Record_QuantityExpected != Record_QuantityObtained) {
          $(this).hide();
        }
      } else if (type == "2") {
        if (Record_LidExpected == Record_LidObtained) {
          $(this).hide();
        } else if (Record_QuantityExpected == Record_QuantityObtained) {
          $(this).hide();
        }
      } else if (type == "0") {
        $(this).show();
      }
    });
  });
});
galambalazs
You're right Galambalazs, I accepted your answer, but I'm still going to use the switch over the if/else.Thanks a lot for teaching me a few basics.
Hallaghan
Your're welcome. `switch` / `if-else` is equally good. You just didn't seem to know that an `else` + `if` can become one `else if`. This is something I wanted to point out.
galambalazs
I just tried to run the script but it is still too slow for the browser to handle, it hangs on the browser, actually.I forgot to mention that the said table can go up to thousands and thousands of rows being loaded from the database.It was not my choice to do things this way but I got to be able to hide rows depending on the selection from the dropdown.Could you give me a hand?
Hallaghan
@Hallaghan, just curious to know what you un-accepted my answer and chose this one instead? Especially because this one has very obvious errors. I am not upset, just curious.
jessegavin
I've uploaded a wrong version, yay. But now it has **no errors**. I ran jslint on it.
galambalazs
@Hallaghan can you post an url? Maybe you will need to do some things without jQuery, because there are situations when it can't scale.
galambalazs
Unfortunately I don't have the project online, at least not my version. It's a private website.
Hallaghan
Yeah, if you're dealing with thousands and thousands of table rows you might need to go back to the drawing board on this one. jQuery is probably not a good solution here.
jessegavin
we don't need the whole project. :) The related part is enough (the form). Post it to http://jsbin.com/ for example, so we can see it.
galambalazs