Brockmann: "Creating Rich Web
Applications Gets a Ton Easier"

e-grou chooses Visual WebGui
over standard ASP.NET

Quick migration of VB 6.0
Applications to the Web

Fully functional software versions
for 30 days evaluation period

Download the free edition of the
Visual WebGui Studio
 

Code Snippets

jr365 posted on July 21, 2009 :: 1274 views

Standard ajax involves a heavy use of client side timers. Visual Web Gui shields developers from alot of the messy details, but there are times when you have to get messy. I want to filter data based on the value in a textbox. However, I don't want to require a button click or enter press, and I don't want to handle all the keypress events on the server as postbacks. Take this for example:

 

googleajaxexample

All I did was type kite, and some search results were returned. To accomplish this in Visual Web Gui, we could handle each textchanged event on the server, but this requires a postback for every key press. Not a good solution for the web. The original idea was to create a client side timer that would be started when the text was changed. I collaborated with Ryan Hatch, who did all of the coding, to put this together - thanks, Ryan!

Here is a live demonstration:

As you can see, we've got 2 ways to fire the events: while typing is occurring, or after typing is completed. That behavior is set here:

ResetTimerProperty

How does this work? First, a quick look at the Visual Studio Solution:

ClientTimedTextboxClientSolution

Ryan took the TextBox.js and TextBox.xslt files from the VWG Sources folder, modified them, and created a class that inherits from the TextBox class:

   16 public partial class TimedTextBox : TextBox

   17 {

   18    public TimedTextBox()

   19    {

   20       InitializeComponent();

   21    }

   22 

   23      /// <summary>

   24      /// Number of milliseconds that the timer will run before KeyPress event is raised

   25      /// </summary>

   26      [Description("Number of milliseconds that the timer will run before KeyPress event is raised")]

   27      public int TimerLength { get; set; }

   28 

   29      /// <summary>

   30      /// Sets whether or not a running client timer will be reset when a key is pressed on the client.

   31      /// </summary>

   32      [Description("Sets whether or not a running client timer will be reset when a key is pressed on the client.")]

   33      public bool ResetClientTimerOnKeyPress { get; set; }

   34 

   35      protected override void RenderAttributes(Gizmox.WebGUI.Common.Interfaces.IContext objContext, Gizmox.WebGUI.Common.Interfaces.IAttributeWriter objWriter)

   36      {

   37          objWriter.WriteAttributeString("TimerLength", TimerLength);

   38 

   39          if (this.ResetClientTimerOnKeyPress == true)

   40             objWriter.WriteAttributeString("ResetClientTimerOnKeyPress", 1);

   41          else

   42             objWriter.WriteAttributeString("ResetClientTimerOnKeyPress", 0);

   43 

   44          base.RenderAttributes(objContext, objWriter);          

   45      }

   46 

   47 }

We added 2 properties:

  • TimerLength: Number of milliseconds that the timer will run before code is executed
  • ResetClientTimerOnKeyPress: A boolean value that sets whether or not a running client timer will be reset when a key is pressed on the client.

And we've overriden the RenderAttributes() method in the base class to include these properties as attributes in the html output. TimedTextBox.xslt: here we've added a an event handler to the html textbox, to call a javascript method:

   71 <!--This is our hook into JavaScript, using OnKeyPress-->

   72 <xsl:attribute name="onkeypress">mobjApp.TimedTextBox_SetTimer('<xsl:value-of select="@Id"/>',this,window);mobjApp.TextBox_KeyPress('<xsl:value-of select="@Id"/>','<xsl:value-of select="@Attr.CharacterValidationMask"/>','<xsl:value-of select="@Attr.CharacterValidationExpression"/>',window,this,event);</xsl:attribute>

and here are the javascript methods: TimedTextBox.js

   15 // Called whenever the user changes text in textbox

   16 function TimedTextBox_SetTimer(strGuid, objInput, objWindow) {

   17 

   18    // Get Current TimerID

   19    var myTimerID = Data_GetAttribute(strGuid, "TimerID");

   20 

   21    // Get ResetTimerOnKeyPress Flag

   22    var myResetTimerOnKeyPress = Data_GetAttribute(strGuid, "ResetClientTimerOnKeyPress");

   23 

   24    // Is there a Timer already running?

   25    var myHasTimerRunning = false;

   26    if (myTimerID != null && myTimerID != 'null') { myHasTimerRunning = true; }

   27 

   28    // Should we start a new Timer?

   29    if (myResetTimerOnKeyPress == 1 || myHasTimerRunning == false) {

   30 

   31         // Create TimerID

   32         var myNewTimerID = TimedTextBox_CreateGuid();

   33 

   34         // Set Current TimerID

   35         Data_SetAttribute(strGuid, "TimerID", myNewTimerID);

   36 

   37         // Create Callback

   38         var myFunction = function() { TimedTextBox_TimerExpired(myNewTimerID, strGuid, objInput, objWindow); };

   39 

   40         // Get Timer Length

   41         var myTimerLength = Data_GetAttribute(strGuid, "TimerLength");

   42 

   43         // Start Timer

   44         var myTimeout = Web_SetTimeout(myFunction, myTimerLength);

   45    }

The behavior of the textbox is determined by attributes that we set earlier. Line 44 invokes VWG code that starts a timer, and then executes code when the timer is complete. Here is the code when the timer is complete:

   49 function TimedTextBox_TimerExpired(strTimerID, strGuid, objInput, objWindow) {

   50 

   51    // Get Current TimerID

   52    var myTimerID = Data_GetAttribute(strGuid, "TimerID");

   53 

   54    // Is our TimerID the latest TimerID?

   55    // We need this because - If user keeps typing, multiple timers will be running at once.  Especially with the ResetClientTimerOnKeyPress flag

   56    if (strTimerID == myTimerID) {

   57 

   58         // Clear Timer - VWG Bug - setting null actually sets it to string 'null'!

   59         Data_SetAttribute(strGuid, "TimerID", null);

   60 

   61         // Raise Event (Fake the EnterKey to get TextChanged to Fire)

   62         TextBox_Change(strGuid, objInput.value, objWindow, true);

   63    }

By checking the TimerId value in line 56, we allow for the behavior to only send a call to the server if the id given for the timer matches what is currently stored in the textbox as an attribute. In line 62, we raise the Textbox_Change event. By the way, don't forget to declare the control in web.config:

   41 <Controls>

   42   <Control Type="MyControls.TimedTextBox.TimedTextBox, MyControls" />

   43   <!--

   44   <Control Type="Gizmox.WebGUI.Forms.Catalog.Controls.WinPanel, Gizmox.WebGUI.Forms.Catalog" />

   45   <Control Type="Gizmox.WebGUI.Forms.WorkspaceTabs, Gizmox.WebGUI.Forms.Extended, Version=3.0.5701.0, Culture=neutral, PublicKeyToken=85eae29607c9f5f3" />

   46   <Control Type="Gizmox.WebGUI.Forms.WatermarkTextBox, Gizmox.WebGUI.Forms.Extended, Version=3.0.5701.0, Culture=neutral, PublicKeyToken=85eae29607c9f5f3" />

   47   <Control Type="Gizmox.WebGUI.Forms.SurfacePanel, Gizmox.WebGUI.Forms.Extended, Version=3.0.5701.0, Culture=neutral, PublicKeyToken=85eae29607c9f5f3" />

   48   <Control Type="Gizmox.WebGUI.Forms.Editors.FCKEditor, Gizmox.WebGUI.Forms.Extended, Version=3.0.5701.0, Culture=neutral, PublicKeyToken=85eae29607c9f5f3" />

   49   <Control Type="Gizmox.WebGUI.Forms.Charts.Chart, Gizmox.WebGUI.Forms.Charts, Version=3.0.5701.0, Culture=neutral, PublicKeyToken=f1bb83df6a8597fb" />

   50   <Control Type="Gizmox.WebGUI.Forms.*, Gizmox.WebGUI.Forms.Office, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d50c2c7452ba77d9" />

   51   -->

   52 </Controls>

Caveat: Does not yet work on multiline textboxes.

This is a working concept that we hope can be integrated into the standard VWG textbox.

Download Code

Note: Codes are submitted as a .zip file to shorten your download time. After downloading it, you will need a program like Winzip to decompress it.

Terms of Agreement:
By using this code, you agree to the following terms...

  1. You may use this code in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this code (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.
  3. You may link to this code from another website, but ONLY if it is not wrapped in a frame.
  4. You will abide by any additional copyright restrictions which the author may have placed in the code or code's description.

Post Rating

Comments

# jr365
Please consider this solution broken, as there are some problems with our approach to inheritance.

We've got a different implentation of the same control, and it can be found here: http://bit.ly/Qmm7k
Posted by jr365 on Monday, September 14, 2009 2:45 PM

Post Comment

Only registered users may post comments.
Most promising startups
Top 3 most promising startups in 2009
   AJAX Framework | Web Development | Cloud applications | RIA Development | Silverlight Applications | Legacy Migration
The most popular open source Ajax applications framework for enterprises | Sitemap | Terms Of Use | Privacy Statement
Copyright © 2005-2009 Visual WebGui®    Design By: Template World
   
Visual Studio Partners