3

I want to set values for objects after the DOM has loaded completely. Problem is, I'm getting a null pointer exception after calling a OnBlur and OnFocus event from a textbox. What am I doing wrong?

javascript:

$(document).ready(function () {
    var sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last()
});

var tempThursdayHrs = 0.0;
function BlurThursdayHrs(sender, args) { sumThursdayHrs.text(tempThursdayHrs + sender.get_value()); }
function FocusThursdayHrs(sender, args) { tempThursdayHrs = sumThursdayHrs.text() - sender.get_value(); }

markup:

<telerik:RadNumericTextBox ID="txtThursdayHrs" runat="server" NumberFormat-DecimalDigits="1"
        Width="25px" MinValue="0" Type="Number" DbValue='<%# Eval("ThursdayHrs") %>'>
        <ClientEvents OnBlur="BlurThursdayHrs" OnFocus="FocusThursdayHrs" />
</telerik:RadNumericTextBox>

error:

Microsoft JScript runtime error: 'sumThursdayHrs' is undefined

Jean-François Beaulieu
  • 4,305
  • 22
  • 74
  • 107

4 Answers4

3

As you said in the heading, the values are set in a function (the ready-event-handler function). But JavaScript has function scope, and as you declared sumThursdayHrs to be a local (not to say "private") variable by using the var keyword, it is undefined from outside. Two possibilites:

  • Make sumThursdayHrs a global variable (remove "var") (and eventually declare it outside). Note that global variables should be avoided where possible to preclude naming conflicts and co
  • or take all functions using it into the same scope. Watch out, then these function will also be no more globally available so you need to set the blur/focus handlers in the same context (as Patrick Scott suggested).
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Please note that you are creating an implied global variable, and although this works, it is bad coding practice. Global variables should be avoided, but if I can't stop you from doing so, at least follow my advice on Global Abatement and see this answer for more info on global variable scope http://stackoverflow.com/questions/10096504/scope-of-javascript-variables-xul-related/10096806#10096806 – Patrick Lee Scott Apr 17 '12 at 21:27
  • for the first suggestion that is (removing var) – Patrick Lee Scott Apr 17 '12 at 21:28
2

if you are using jquery already why not bind the events with jquery?

$('span[id$="txtThursdayHrs"]:first').on("focus", FocusThursdayHrs)
          .on("blur", BlurThursdayHrs);

Also, declare those function inside the doc ready function, so they can access sumThursdayHrs, or use anonymous functions in the same place instead of calling the functions

Ex:

$(document).ready(function () {
    var sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last();
    var tempThursdayHrs = 0.0;
    $('span[id$="txtThursdayHrs"]:first').on("focus", function() {
        sumThursdayHrs.text(tempThursdayHrs + $(this).val());
    })
    .on("blur", function() {
        tempThursdayHrs = sumThursdayHrs.text() - $(this).val();
    });
});

Or move sumThursdayHrs to a global object... For sanity's sake, I recommend not putting it in window though.

Instead define a global namespace to hold your app specific global variables. This is called global abatement.

Ex.

var MyApp = {};
$(document).ready(function () {
    MyApp.sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last();
    //...

--

MyApp.tempThursdayHrs = 0.0;
function BlurThursdayHrs(sender, args) { MyApp.sumThursdayHrs.text(MyApp.tempThursdayHrs + sender.get_value()); }
function FocusThursdayHrs(sender, args) { MyApp.tempThursdayHrs = MyApp.sumThursdayHrs.text() - sender.get_value(); }
Patrick Lee Scott
  • 8,217
  • 3
  • 36
  • 42
1

The error is due to scoping:

$(document).ready(function () {
    // sumThursdayHrs is a *local* variable to the function
    var sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last()
});

// ... so this will fail because it is trying to use
// window.sumThursdayHrs (the property sumThursdayHrs on the window object),
// which is not set and thus the Reference Error
function BlurThursdayHrs(sender, args) {
    sumThursdayHrs.text(tempThursdayHrs + sender.get_value());
}

The "simple fix" (which may or may not be valid) is:

$(document).ready(function () {
    // Set the "global variable" sumThursdayHrs
    // "window." isn't technically required, but it is to show a point.
    window.sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last()
});

Happy coding.

0

I'm not sure if that code example you gave are in the same bag or not but if you've defined a variable inside the $(document).ready(), know that the variable is inside a closure. Outside of it, it'll be undefined.

So why not do this:

$(document).ready(function () {
    var sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last();

    var tempThursdayHrs = 0.0;

    function BlurThursdayHrs(sender, args) {
        sumThursdayHrs.text(tempThursdayHrs + sender.get_value());
    }

    function FocusThursdayHrs(sender, args) {
        tempThursdayHrs = sumThursdayHrs.text() - sender.get_value();
    } 
});

In the above code, it should pick up the value you intended because everything is inside the $(document).ready() closure. And in addition, you've assigned a jquery object, $('span[id*="lblThursdayHrs"]'), into a variable, so it must be used inside the jquery environment not outside... In 1 word, if you're using jquery then keep it in jquery environment.

What you did is, you've signed a contract with jquery that you'll be using all its methods and properties by doing var sumThursdayHrs = $('span[id*="lblThursdayHrs"]').last(). Once you use $(something), that's it, it must be used inside the jquery environment.

Shaoz
  • 10,573
  • 26
  • 72
  • 100