How do you Validate Data on Web Form

Hi,

I’ve been struggling with the best way to do this. What I have come up with first is on the fields lost focus event if the data isn’t valid I change the style of the control to have a Red bg. I then allow them to go to the next field.

The form is in a container, the Next button is on the form. It calls code that makes that one invisible and the next one visible. The problem is I can’t figure a way to check if any of the fields are in an error state.

The other issue is to stop the user from just hitting the next button without filling in all the fields.

Any ideas out there?

Thanks

Rich

One way would be to refactor the validity checks away from the LostFocus events and into methods that are called by the events. Then when the user clicks Next you could double check each field and refuse to move next if one or more are invalid.

Sorry I don’t understand what you mean be refactor?

I did it by creating subclasses of the standard controls and adding properties and methods to keep track of the “required” and “validation” statuses. When data in a control is changed it automatically updates these statuses and sets whatever indicator. Then in the ok/save/next button action, loop through the controls (or a separate array) to check the statuses.

Right now your validation code is in the LostFocus event for each field, right? Move that code to a method that checks the whole form (i.e. ValidateForm), or to methods that check each field (i.e. ValidateFirstName, ValidateEmail). Now you can call the validation code from the LostFocus event (Self.ValidateWhatever) and the click on the Next button.

Subclassing controls to track validation and/or support a set of validator methods/classes, as Jay suggests, can be even more useful and flexible.

Where exactly does the validation happen, on the server or on the browser? If it happens on the server, then it could generate a lot of post back traffic and slowness, no?

The validation happens on the server. All the client events send back information to server, so it is not good practice to validate on each lostfocus event. When you press the button “Save”, then validate all the fields and change the style of the specific webfield, which it does n’t follow your validation.

In PushButton.Action :

If Editfield1.Text = "" or EditField2.Text = "" then
MsgBox("Field(s) empty. Please complete the form")
Return
end if

Xojo is nice in that you can validate on the LostFocus event if the field. So the user gets instant feedback. Not at the time the submit is hit. It is very fast (instant by the user, unless he is using some sort of morse code uplink from the jungle…)

If me.text ="" then me.style=MyInvalidStyle else me.style=MyValidStyle end if

Live example is here: http://insurehomehealth.com/contact.html

I tried to loop through the controls but couldn’t get it to work. I finally gave up and checked each one. What did I do wrong.

I have about 10 fields i have to validate. All the controls Text fields and a couple of popmenus, they are all on a container control. The submit button is on the Window.

Lets day the window is called Win1 and the container is called Con1

This code is in a method of the container. Heres the code:

   Dim lnX, lnCount As Integer
    Dim IbValid, lbReturnVal as Boolean
    
for lnX = 0 to lnCount
    IbValid = False
    if Con1.ControlAtIndex(lnX) IsA WebTextField then
      If DidValidate(Con1.ControlAtIndex(lnX).Name) then IbValid = True
    end
    if Con1.Control(lnX) IsA CheckBox then
      CheckBox(Con1.Control(lnX)).Value = False
    end
    if Con1.Control(lnX) IsA ComboBox then
      ComboBox(Con1.Control(lnX)).ListIndex = -1
    end
    if Con1.ControlAtIndex(lnX) IsA WebPopupMenu then
      if WebPopupMenu(Con1.ControlAtIndex(lnX)).ListIndex > -1 then IbValid = True
    end
    if not lbReturnVal then
      lbReturnVal = IbValid
    end
    
  next
  Return lbReturnVal
    
  • Where do you set lnCount? It should = Con1.ControlCount-1 (index is 0-based).

  • It looks to me like your “if not lbReturnVal then” section will cause the code to return True if any single control is valid. I would think that you would want to return True only if all of them are valid. So…

Dim lbReturnVal as Boolean = True
...
lbReturnVal = lbReturnVal And IbValid 'If IbValid is ever false, lbReturnVal will end up false.

This would require making IbValid = True at the top of each loop because you’re using the loop to do other stuff so some iterations may never have a validity check.

Actually that part is all wrong I know, it’s the looping through the controls.

And lnCount is getting set. I will try and clean up the code and tell you the exact errors I’m getting.

Thanks

OK Here is the correct Info.

I have this Method that checks all controls that need validation. This is called from the lost focus like this:

Call DidValidate(Me)

Here is that method:

    'Returns true if field validated 
  
  Dim ln as Integer
  Dim lbValid as boolean
  lbValid = True
  
  
  
  lbObj.Style = EntryFields
  if lbObj.Name = "txtSecondaryEmail" and lbObj.Text = "" then
    Return lbValid
  end
  
  if lbObj.Name = "txtPhoneHome" or  lbObj.Name = "txtPhoneCell" then
    if lbObj.Text = "" then
      txtPhoneHome.Style = EntryFieldsError
      txtPhoneCell.Style = EntryFieldsError
      lbValid = False
    else
      txtPhoneHome.Style = EntryFields
      txtPhoneCell.Style = EntryFields
    end
    
  end
  
  if lbObj.Text = "" then
    lbObj.Style = EntryFieldsError
    Return False
  end
  
  
  Select Case lbObj.Name
    
  case "txtFirst"
    if lbObj.Text <> "" then
      txtNick.text = lbObj.Text
    end
    
  Case "txtBDayDay"
    ln = lbObj.Text.Val
    If ln < 1 or ln > 31 then
      lbObj.Style = EntryFieldsError
      lbValid = False
    end
    
  Case "txtBDayMonth"
    ln = lbObj.Text.Val
    
    If ln < 1 or ln > 12 then
      lbObj.Style = EntryFieldsError
      lbValid = False
    end
    
  Case "txtBDayYear"
    ln = lbObj.Text.Val
    
    If ln < 1914 or ln > 2114 then
      lbObj.Style = EntryFieldsError
      lbValid = False
      Exit
    end
    
    Dim ldBDay As Date
    Dim sDate as String
    sDate = txtBDayMonth.text + "/" + txtBDayDay.Text + "/" + txtBDayYear.Text
    
    If not validDate(sDate, ldBDay)  then
      lbObj.Style = EntryFieldsError
      lbValid = False
    end
    
  Case "txtPrimaryEmail", "txtSecondaryEmail"
    
    If not ValidateEmail(lbObj.Text) then
      lbObj.Style = EntryFieldsError
      lbValid = False
    end
    
  end
  
  Return lbValid

This code works to validate the individual controls, where the problem is if the user skips over controls and tries to go to the next container, Making this container invisible and making next one visible. I try and loop through the controls to check the entire form.

Here is the looping code, getting compiler error (Parameter not compatible with this function) on
IbValid = DidValidate(WebContainer.ControlAtIndex(lnX).Name)

  'loop through controls to validate each one.
  
  Dim lnX, lnCount As Integer
  Dim IbValid, lbReturnVal as Boolean
  lbReturnVal = True
  
  lnCount = Self.ControlCount - 1
  
  for lnX = 0 to lnCount
    IbValid = False
    if WebContainer.ControlAtIndex(lnX) IsA WebTextField then
      IbValid = DidValidate(WebContainer.ControlAtIndex(lnX).Name)        '<<<-----Parameter not compatible with this function
    end
    if WebContainer.ControlAtIndex(lnX) IsA WebPopupMenu then
      IbValid = (WebPopupMenu(WebContainer.ControlAtIndex(lnX)).ListIndex > -)
    end
    if not IbValid then
      lbReturnVal = IbValid
    end
    
  next
  Return lbReturnVal

How can I do this.

In LostFocus you call DidValidate(Me). You pass the control instance. But in the loop you’re passing the control name, a string. I don’t see the actual declaration for DidValidate, but I’m guessing lbObj is the input parameter, i.e. you need to pass the object cast to the correct type:

if WebContainer.ControlAtIndex(lnX) IsA WebTextField then
Dim objTextField As WebTextField
objTextField = WebTextField( WebContainer.ControlAtIndex(lnX) ) 'This is how you cast types in Xojo.
IbValid = DidValidate(objTextField)

Also, you forgot the -1 in this line, there’s just a -:

IbValid = (WebPopupMenu(WebContainer.ControlAtIndex(lnX)).ListIndex > -1)

FYI - you may want to consider an OOP solution to validation in the future. Having a long method where you work off the control name becomes difficult to modify and maintain, though for right now it can certainly work.

Thank you so much. I would like to do more oop, it’s just more convenient not to spend time on it when I have a deadline looms.

In a few short words how would one do this in oop.

Thanks again!