views:

186

answers:

6

Hi,

EDIT: I am also after advice if there is a better way to go about this??

I have a webpage that displays a timesheet for the user to fill out. The timesheet is for a month so it has as many rows in the month and also 5 columns of data, Normal hours, extended hours, shift hours holidays hours and total.

I have a dropdown list that allows the user to select the month and year textbox.

When they select a month the code then disbles the bottom rows if they are not required due to not havving say 31 days as an example. It also then sets the background color of each row depending on if it is a weekend( in a different color) or not.

Problem is when the month is selected it is taking 3-4 secs to run the code and is annoying for the user as they dont know what is happening.

Is there any way of improving this that you can see? The code is shown below.

 $('[id$=lstMonth]').change(function() {
  MonthChange();
 });   
});

function MonthChange() {

 var month = parseInt($('[id$=lstMonth]').val())-1;
 var year = $('[id$=txtYear]').val();
 var daysInMonth = GetDaysInMonth(month, year);
 var day, dte, bgcolor;

 for(day=28; day<=31; day+=1) {
  if(day > daysInMonth)
   DisableRow(day);
  else
   EnableRow(day);
 }

 for(day=1; day<=daysInMonth; day+=1) {
  dte = GetDate(day, month, year);
  bgcolor = GetInputFieldColor(dte, false);
  SetBackgroundColor(day, bgcolor);
 }
}

function SetBackgroundColor(day, bgcolor) {
 var selector = '[id$=txtNormal' + day + ']';

 $(selector).css("background-color", bgcolor);
 $(selector).parent().css("background-color", bgcolor);

 selector = '[id$=txtExtended' + day + ']';
 $(selector).css("background-color", bgcolor);
 $(selector).parent().css("background-color", bgcolor);

 selector = '[id$=txtShift' + day + ']';
 $(selector).css("background-color", bgcolor);
 $(selector).parent().css("background-color", bgcolor);

 selector = '[id$=txtHoliday' + day + ']';
 $(selector).css("background-color", bgcolor);
 $(selector).parent().css("background-color", bgcolor);

 selector = '[id$=txtTotal' + day + ']';
 $(selector).css("background-color", bgcolor);
 $(selector).parent().css("background-color", bgcolor);
}

function DisableRow(day) {
 var selector = '[id$=txtNormal' + day + ']';

 $(selector).css("background-color", "red");
}

function EnableRow(day) {
 var selector = '[id$=txtNormal' + day + ']';

 $(selector).css("background-color", "blue");
}
+2  A: 
function SetBackgroundColor(day, bgcolor) {
        var selector = '[id$=txtNormal' + day + ']';    
        $(selector).css("background-color", bgcolor);
        $(selector).parent().css("background-color", bgcolor);
}

=>

function SetBackgroundColor(day, bgcolor) {
        var selector = '#txtNormal' + day;
        var obj = $(selector);
        obj.css("background-color", bgcolor);
        obj.parent().css("background-color", bgcolor);
}

There are many tips how to improve performance for jQuery.

Arnis L.
What does this do to performance?? Also due to webforms it puts a prefix infront off control ids.
Malcolm
Performance will improve in this example because you are not constantly asking jQuery to search the DOM-tree with all of those $(selector) statements.With Arnis's example, he calls $(selector) once, assigns its resulting jQuery-object to a variable called "obj", then references that variable in the following statements.Indeed, you could also assign the result of $(selector).parent() to a variable and reference that too, but the improvements will not be as drastic.In general, anything you do to limit the number of $() calls you make before acting on the results will improve performance.
brownstone
You selected the same object over and over again. Instead of that you can select it only once and use it.
Arnis L.
"Also due to webforms it puts a prefix infront off control ids."=>selectors by id are fastest ones because calls document.getElementById('..') JS function and doesn't iterate through element collections. Use them if they are available.
Arnis L.
+1  A: 

You are using all over your code, attribute selectors without specifying the element type.

This is not well performing, since all your DOM elements are inspected, for example:

You are also using endsWith [id$=xxx] this is really needed for your case??

I would consider rewriting your SetBackgroundColor function as this also for readability:

function SetBackgroundColor(day, bgcolor) {
  var types = ['Normal', 'Extended', 'Shift', 'Holiday'];

  $.each(types, function(index, type){
    var selector = 'input[id$=txt' + type + day + ']'; // change input to your
                                                       // element type
                //'#txt' + type + day; or if you don't need the endsWith selector
    $(selector).css("background-color", bgcolor)
               .parent()
               .css("background-color", bgcolor);
    // 1 selector call, and using chaining
  });
}
CMS
A: 

I would use the profiler in Firebug to see where time is spent in the code. Here's another thread with some explanation on how to use it.

Richard Nienaber
A: 
bgcolor = GetInputFieldColor(dte, false);
SetBackgroundColor(day, bgcolor);

I'd suggest to join Get... and Set... functions into one, which obtains DOM selectors only ones.

Thevs
+1  A: 

I'm guessing that the fields that have the prefix txt are all textboxes? Then your CSS selectors will be much more efficient if you specify a tag name for the element that has to be fetched with the proposed ID. Something like this:

selector = 'input[id$=txtExtended' + day + ']';

And then chain the different operations together so you fetch every element only once like CMS proposes in his answer.

The problem with specifying no tag name is that jQuery has to fetch all elements and check if their id attribute is corresponding to the selector. If you specify a tag name, getElementsByTagName can be used and only the elements that have the specified tag name will be fetched.

Another performance increase is to search the given element as a child of another element. You can compare it to specifying a certain 'range' in which jQuery should search all elements that match the given selector like this:

$('input[id$=txtExtended' + day + ']', $element);

If this doesn't increase performance enough you could post the HTML snippet of a certain row, it would be easier to see where the performance problem sits.

PeterEysermans
A: 

If all of those elements you are selecting are of the same type then prefix the attribute selector. This will speed the match up.

e.g

$('input[id$=something]')
redsquare