Solved

Smart Navigation & form refocusing

Posted on 2004-08-31
18
529 Views
Last Modified: 2008-02-01
Now with smart navigation and the cursor jumping back to the textbox I just changed the value of:  I have several textboxes that take in dollar amounts and then a label (lblGrandTotal) below them that displays the sum of all amounts entered into the textbox.  So each of my textboxes have text_changed methods that cause the label to be updated with the new total.   For intstance:
Private Sub txtTaxiTotal_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtTaxiTotal.TextChanged
        txtTaxiTotal.Text = FormatCurrency(txtTaxiTotal.Text)
        Dim grandTotal As Double
        grandTotal = CDec(lblAirTotal.Text) + CDec(lblLodgingTotal.Text) + CDec(lblPDTotal.Text) + CDec(lblCarTotal.Text) + CDec(lblPhoneTotal.Text) + CDec(txtParkingTotal.Text) + CDec(lblMilesTotal.Text) + CDec(txtTaxiTotal.Text) + CDec(txtBaggageTotal.Text) + CDec(txtTuitionTotal.Text) + CDec(txtOtherTotal.Text)
        lblGrandTotal.Text = FormatCurrency(grandTotal)
    End Sub

When I change the value in txtTaxiTotal and then click to the next textbox in the list to change it's value, you can see the postback fire, the lablel is updated with new value, but the cursor then jumps right back to txtTaxiTotal.  After that if I click to another textbox or anywhere else on form the cursor will then go and stay where I point it, so it just happens the first time I try to click out of it.  I know it's being picky but my form has many inputs that fire changed events and this will become annoying to my users.  Thanks for the help!
0
Comment
Question by:jacobymatt
  • 10
  • 6
  • 2
18 Comments
 

Author Comment

by:jacobymatt
ID: 11943404
sorry, that was a cut & paste...I meant to introduce that piece with the fact that I turned on smart navigation on this page and that took care of the problem I was having which was each time a value was entered in any form element with auto postback turned on, the form would then refocus back to the original spot it focuses to during form load (center?) which would cause the user to continuously scroll back to where they were on the form to enter the next value.  Smart navigation fixed this, it stays focused where the value has been entered or changed, but now the cursor jumps back to the element I just changed when I try to click out of it the first time.  
0
 
LVL 8

Expert Comment

by:boulder_bum
ID: 11943791
As a friendly warning, Smart Navigation, however tempting, is horribly buggy and sometimes ends up wrecking scripts, hiding elements, blanking out pages, etc.

As much as it sucks, you'd probably be better off rendering your own javascript focus()/ scroll position.

http://weblogs.asp.net/ksamaschke/archive/2003/04/27/6085.aspx
0
 

Author Comment

by:jacobymatt
ID: 11954793
well, I tried what that article had posted but the form is still refocusing to the form center.  So here is an envent handler I have for one of my textboxes:
Private Sub txtParkingTotal_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtParkingTotal.TextChanged
        txtParkingTotal.Text = FormatCurrency(txtParkingTotal.Text)
        Dim grandTotal As Double
        grandTotal = CDec(txtAirTotal.Text) + CDec(txtLodgingTotal.Text) + CDec(txtPDTotal.Text) + CDec(txtCarTotal.Text) + CDec(txtPhoneTotal.Text) + CDec(txtParkingTotal.Text) + CDec(txtMilesTotal.Text) + CDec(txtTaxiTotal.Text) + CDec(txtBaggageTotal.Text) + CDec(txtTuitionTotal.Text) + CDec(txtOtherTotal.Text)
        txtGrandTotal.Text = FormatCurrency(grandTotal)
        Page.RegisterClientScriptBlock("focus", _
      "<script language=""JavaScript"">" & _
         "document.txtParkingTotal.focus();" & _
      "</script> ")
    End Sub

I have smart navigation turned off and when I change the value of txtParkingTotal the form posts back and resets the form to the center, forcing me to scroll back to where I was to enter the next value.  There are no errors but it just doesn't work. Help!
0
 

Author Comment

by:jacobymatt
ID: 11957944
okay...well I got the focus working finally without smart navigation using the following javascript:

Private Sub txtParkingTotal_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtParkingTotal.TextChanged
txtParkingTotal.Text = FormatCurrency(txtParkingTotal.Text)
        Dim grandTotal As Double
        grandTotal = CDec(txtAirTotal.Text) + CDec(txtLodgingTotal.Text) + CDec(txtPDTotal.Text) + CDec(txtCarTotal.Text) + CDec(txtPhoneTotal.Text) + CDec(txtParkingTotal.Text) + CDec(txtMilesTotal.Text) + CDec(txtTaxiTotal.Text) + CDec(txtBaggageTotal.Text) + CDec(txtTuitionTotal.Text) + CDec(txtOtherTotal.Text)
        txtGrandTotal.Text = FormatCurrency(grandTotal)
 Page.RegisterStartupScript("focus", _
 "<script language='javascript'>" & _
 "document.getElementById('txtParkingTotal').focus()" & _
      "</script>")
    End Sub

But I'm still running into the problem I had with smart navigation which is that when the form posts back and sets the focus to txtParkingTotal it also resets the cursor there, even though I had to click inside a different element or on anywhere else on the form to get the changed even to fire.  

** Now that I've had time to think about this I guess what I really want is for the form to not refocus at all because it will not make sense for the focus to go one place and the cursor to go another.  The only reason I was ever messing with the focus is because the auto postback I have on my elements causes the form to refocus to the form center.  So to keep all this from happening should I perform all of my text changed event handlers in javascript on the client side?  This way I could turn auto postback off, the focus would not reset when I left the textbox, and the cursor would go wherever I clicked to.  Can someone tell me if I am right on this or if there is another way to accomplish this and still use the autopostback?  
0
 
LVL 8

Expert Comment

by:boulder_bum
ID: 11958944
Besides focusing, you may want to reset the scroll position. Fortunately, this guy built a control to do just that for you:
http://www.codeproject.com/aspnet/AspNetScrollbarMove.asp


"Page.RegisterClientScriptBlock("focus", _
      "<script language=""JavaScript"">" & _
         "document.txtParkingTotal.focus();" & _
      "</script> ")"


Maybe use Page.RegisterStartupScript(). Said function puts the script near the bottom of the page to make sure everything's loaded (document.txtParkingTotal may not exist at the point the script executes).
0
 

Author Comment

by:jacobymatt
ID: 11964668
None of this is working for me.  Can someone please either tell me how I can get the focus to go to the element the user clicks onto to leave the element with the text changed property.  So textbox1 has the textchanged property.  The user changes the value and then clicks into textbox2.  The textchanged property should fire for textbox1 but the focus and even better the cursor should be on textbox2.  I cant believe more people aren't having to deal with this.  If this is impossible then please tell me how I can make javascipt take care of the logic I need to peform that I showed above for txtParkingTotal.  Just the part where it formats the text entered to currency and adds the value to the other textboxes to get the grand total.  I will award the points for an answer to either the javascript or the other solution.    
0
 

Author Comment

by:jacobymatt
ID: 11965831
Bumping points up again, really need help with this!
0
 
LVL 15

Expert Comment

by:Thogek
ID: 11965848
Here's an idea you can try (disclaimer: untested):

First, set up SmartNavigation for your page, as described in previous comments above.

Second, make sure that *all* of your form's elements (whether simple <input> and <select> tags, or server-side <asp:TextBox>-type tags) have TabIndex attributes, and that the values of these TabIndex attributes are all numbers in the order in which a user should be able to tab through them.  (See http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/tabindex.asp and/or http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemwebuiwebcontrolswebcontrolclasstabindextopic.asp for more about the TabIndex attribute.)

Third, in your page's ASPX file, add something like the following within the <head>...</head> section:

    <script language="JavaScript" type="text/javascript">
    function TabToNextField() {
        var oFocus = document.activeElement;
        if(oFocus) {
            var oForm = oFocus.form;
            if(oForm) {
                var intCurTab = oFocus.tabIndex;
                var oNext = null;
                for(var i = 0;  i < oForm.elements.length;  ++i)
                    if(oForm.elements[i].tabIndex == intCurTab + 1)
                        oForm.elements[i].focus();
            }
        }
    }
    </script>
   
And adjust the <body> tag to include an onload="TabToNextField()" attribute.
    <body onload="TabToNextField()">

Then run your page again and see if that does any good.
0
 
LVL 8

Expert Comment

by:boulder_bum
ID: 11966543
"Can someone please either tell me how I can get the focus to go to the element the user clicks onto to leave the element with the text changed property"

You may be thinking that the TextChanged events will fire in the order you changed the TextBoxes, but this is not necessarily the case. Really all that happens is a value gets posted to the server and if it's different than the original value the TextChanged event is raised. Additionally, information about which control has focus isn't transmitted via http (and technically the button is really the last control to have focus).

Basically you need to:

1. Figure out the last TextBox (or control) to have focus.
2. Send information about the control to the server.
3. Have the server render a script to reset focus to the control.

A simple way to handle 1 is to simply loop through all of the controls of your page and assign an OnFocus() function to the proper attribute.

//call this on Page_Load or something with SetFocusScript( this );
private void SetFocusScript( Control c )
{
    foreach( Control current in c.Controls )
         if( current is TextBox )
              current.Attributes.Add( "onfocus", "trackFocus( '" + current.ClientID + "' );" );
       
    //recursion accounts for container controls
    SetFocusScript( current );
}

For 2, you'll need a simple way to post the information. Maybe try a hidden field, then (in the trackFocus javascript function) set it's .value property to the id of the TextBox.

For 3, you'll have the control id posted by the hidden field, so you simply need to insert it's value into the script you have to set control focus.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:jacobymatt
ID: 11968023
Wow.  Again what I think I am really after here is forcing the cursor/tab to go to the control or anwhere on the form that I click to when I click out of the control with the text changed property.  Smart navigation is on and I do have a tab index set for all my controls and as long as I dont change the values I can tab throught the entire form successfully.  But...Right now if I change the value of textbox1 and then hit tab, the form posts back and it does keep it's focus on the changed control, but the cursor jumps back into the control I just changed as well, instead of moving to the next control in the tab index.  It does the same thing if I click anywhere on the form to leave the changed textbox, the cursor goes back to the textbox I tried to click out of.  If I click the tab button again it will make the jump to the next control, but with over 30 textboxes on my form I  really need to keep my user from having to press tab or click out of the textbox twice everytime.  I haven't seen a way to control the cursor, and I'm not sure how work together with the focusing.
0
 
LVL 8

Expert Comment

by:boulder_bum
ID: 11968462
Okay, so let me see if I understand your problem:

*You have 30 TextBoxes and are using smart navigation, and a label tracking the sum of values entered in the TextBoxes.
*Each of the TextBoxes is set up with its AutoPostBack property set to true (posts back each time the TextBox's value changes) so that you can update the label.
*Smart navigation is returning to the control that posted back, when you want the focus to be on the next control in the tab order.

Does that sound right?

My first suggestion if such is the case and you just want to keep a running total is to turn AutoPostBack off and just use a bit of JavaScript accumulate the totals via the TextBoxes' onblur event. It will prevent PostBack altogether which not only fixes the problem, but will improve performance.

Otherwise, I'd still track the ID of the current control (or the current position in the tab order), post that value back, then set the focus via a bit of JavaScript to the next control in the list/order.
0
 

Author Comment

by:jacobymatt
ID: 11968566
Yes, now you've got the picture.  But keep in mind I don't necessarily want the focus to go to the next control in the tab order, unless I do press tab.  If I click to another control on the screen the focus and the cursor should go there, just like it would on a form without autopostback, but I think disabling autopostback and handling the accumulation functions in javascript will accomplish this.  Now...to completely earn this answer can you please tell me how to do this in javascript.  I am very unfamiliar with JS and more specificly the onblur event you mention.  So if this was the code to get this done in my code behind page:

Private Sub txtTaxiTotal_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtTaxiTotal.TextChanged
        txtTaxiTotal.Text = FormatCurrency(txtTaxiTotal.Text)
        Dim grandTotal As Double
        grandTotal = CDec(lblAirTotal.Text) + CDec(lblLodgingTotal.Text) + CDec(lblPDTotal.Text) + CDec(lblCarTotal.Text) + CDec(lblPhoneTotal.Text) + CDec(txtParkingTotal.Text) + CDec(lblMilesTotal.Text) + CDec(txtTaxiTotal.Text) + CDec(txtBaggageTotal.Text) + CDec(txtTuitionTotal.Text) + CDec(txtOtherTotal.Text)
        lblGrandTotal.Text = FormatCurrency(grandTotal)
    End Sub

How do I do this in javascript?  
0
 
LVL 15

Expert Comment

by:Thogek
ID: 11970363
jacobymatt,
Did you try what I suggested above?
0
 

Author Comment

by:jacobymatt
ID: 11973210
Yes I did try that method and did not get anything to work.  I dont think there were errors but it just didnt work.  After reading into this more I think the best solution for me will be to just use javascript to format the text entered to a currency and sum up the other textboxes to get the total like I showed above.  If I do it this way I won't even have to worry about the focusing and my tab index should work just fine becaue smart navigation and autopostback will be turned off.  Can someone please show me how to do the calculations and formatting shown above in javascript?
0
 
LVL 8

Expert Comment

by:boulder_bum
ID: 11974290
Like, maybe have an array of TextBox names:

var names = [ "txtOne", "txtTwo", "etc" ];

Then, have a function like:

//untested. not sure if this works
function SetTotal()
{
    var total = 0.0;

    for( var i = 0; i < names.length; i++ )
       if( document.getElementById( names[i] ).value != "" ) //more validation?
           total += document.getElementById( names[i] ).value;

   document.getElementById( "someControl" ).value = total;
}

Then, in the code-behind, loop through all of the relevant TextBoxes and do this:

textBox.Attributes.Add( "onblur", "SetTotal();" );

If every TextBox is used for the operation, you can simply cut-and-paste this code:

private void SetBlur( Control c )
{
    foreach( Control current in c.Controls )
    {
         if( c is TextBox )
             c.Attributes.Add( "onblur", "SetTotal();" );
         
         //recurse to cover the children of container controls.
         SetBlur( c );
    }  
}

See here for more on OnBlur:

http://www.webreference.com/js/tips/000804.html

There are various ways to spice the above methodology up, but I'm sure you see the basic idea.
0
 

Author Comment

by:jacobymatt
ID: 11974742
This looks like the right direction.  All of my textboxes do not sum up to the same total; I have a several different sums and then some that multiply a rate entered by a number of days entered and other stuff like that so I probably wont use the looping part but instead add the on blur attributes individually.  I have only 2 questions:  Your function settotal() should be in a javascript section of the html on my page, right?  So the only thing that should go in the code behind are the attributes.add methods, right?  Second, how can I format the result to a currency lke in my previous code above?
0
 

Author Comment

by:jacobymatt
ID: 11974756
Oh yea, should the attributes.add( "onblur", "SetTotal();" ); part go on my form load in the code behind page or somewhere else?
0
 
LVL 8

Accepted Solution

by:
boulder_bum earned 150 total points
ID: 11975100
"Your function settotal() should be in a javascript section of the html on my page, right?"

Yeah. Because you have several rows, however, you may want to tweak the script like this:

//untested, not sure if it works
var multiDimArray = [ [ "one", "two" ], ["three", "etc" ] ];
var totalControls = [ "totalOne", "totalTwo" ];

SetTotal( rowNum )
{
   var total = 0.0;

    for( var i = 0; i < multiDimArray[rowNum].length; i++ )
       if( multiDimArray[rowNum][i].value != "" )
             total = total + multiDimArray[rowNum][i].value;

    document.getElementById( totalControls[rowNum] ).value = total;
}

As for the formatting, I'm pretty new to javascript too, so I'm not sure, but I did find this:

http://www.pageresource.com/jscript/j_a_03.htm





0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

One of the pain points with developing AJAX, JavaScript, JQuery, and other client-side behaviors is that JavaScript doesn’t allow for cross domain request for pulling content. For example, JavaScript code on www.johnchapman.name could not pull conte…
User art_snob (http://www.experts-exchange.com/M_6114203.html) encountered strange behavior of Android Web browser on his Mobile Web site. It took a while to find the true cause. It happens so, that the Android Web browser (at least up to OS ver. 2.…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now