#2569 FWT Text Validation

Ron Snyder Fri 14 Oct 2016

I have a form with FWT Text fields, I have a one field where I would like the user to only input a number and then another where for a date. What is the best way to validate these?

SlimerDude Fri 14 Oct 2016

Hi Ron!

A number you can validate at every stage of text entry, so you can give immediate feedback using the Text.onModify() event.

The date is a little more tricky because you have to wait until the user has finished typing before you validate. So I'd be inclined to use the Widget.onBlur() event.

Below is a simple program that uses these events to validate inputs. The background colour of the corresponding Text widget is turned red if invalid.

using fwt
using gfx

class Example {
    Void main() {
        Window {
            it.title = "Validation Demo"
            InsetPane {
                GridPane {
                    it.numCols = 2
                    
                    Label {
                        it.text = "Number:"
                    },
                    Text {
                        it.onModify.add |e| { validateNumber(e) }
                    },
                    
                    Label {
                        it.text = "Date:"
                    },
                    Text {
                        it.onBlur.add |e| { validateDate(e) }
                    },
                },
            },
        }.open
    }
    
    Void validateNumber(Event e) {
        textWidget := (Text) e.widget
        valid := textWidget.text.isEmpty || textWidget.text.toFloat(false) != null
        textWidget.bg = valid ? null : Color.red
    }

    Void validateDate(Event e) {
        textWidget := (Text) e.widget
        valid := textWidget.text.isEmpty || Date.fromLocale(textWidget.text, "DD MMM YYYY", false) != null
        textWidget.bg = valid ? null : Color.red
    }
}

Ron Snyder Fri 14 Oct 2016

Thank you so much for your help and quick reply!

Ron Snyder Tue 18 Oct 2016

I am having a bit of an issue with this, setting the textWidget.bg doesn't change the background color. I can change the text value no problem but the background color remains the same. Here is what I am trying:

setPointNumber := |Event e, Str fieldName| {
          textWidget := (Text) e.widget
          valid := textWidget.text.isEmpty || textWidget.text.toFloat(false) != null
          if(valid){
            Env.cur.out.printLine(textWidget.bg)
            textWidget.bg = Color.green
            points.set(fieldName, e.widget->text)
          }
          else{
            Env.cur.out.printLine(textWidget.bg)
            textWidget.bg = Color.red
            Env.cur.out.printLine(textWidget.bg)
            textWidget.text = ""
            Env.cur.out.printLine("invalid number")
          }
        }

Ron Snyder Tue 18 Oct 2016

Oh, the form is also in a Dialog. Not sure if that makes a difference or not.

SlimerDude Tue 18 Oct 2016

Try this:

setPointNumber := |Event e, Str fieldName| {
    textWidget := (Text) e.widget
    valid := textWidget.text.isEmpty || textWidget.text.toFloat(false) != null
    if (valid) {
        textWidget.bg = Color.green
        points.set(fieldName, e.widget->text)
    } else {
        textWidget.bg = Color.red
        // textWidget.text = ""  // REMOVE THIS LINE!
    }
}

Remember that FWT is all event driven. When you set textWidget.text = "" then setPointNumber is called again, but the empty text is valid, so you set the bg back to green.

If you (really) want to clear the text widget, then you could set the bg colour after you clear the text:

textWidget.text = ""
textWidget.bg = Color.red

But note setPointNumber would still be called twice. You're probably better off setting a flag somewhere which says ignore next valid text event!.

Ron Snyder Wed 19 Oct 2016

Thank you for your help SlimerDude, I really do appreciate it. The problem I am having is that the background color is never displaying on the screen even when I removed setting the text. I tried setting it in the onModify event and setting it by default in the text widget like below but the background always remains white. This is within a fwt dialog if that makes any difference.

myContent.add(Label { text="Billing Days: "})
myContent.add(Text {bg=Color.green; onModify.add{(setPointNumber(it, "billingDays")) }})

SlimerDude Wed 19 Oct 2016

Hi Ron,

Well, I modified the example to run in a Dialog and it still works as expected. So I imagine either there's something else at play with your code, or less likely (but still possible) it's environmental; I'm using Fantom 1.0.69 on Win 7 - 64 bit.

If the problem can't narrowed down any more, then you could email me larger chunks of code and I'll see if I can't help you out offline. You can find a valid email address at the bottom of Alien-Factory.

Dialog example code follows:

using fwt
using gfx

class Example {
    Void main() {
        
        Window {
            win := it
            title = "Validation Demo"
            add(Label { text = "The Window" })
            onOpen.add |ee| {
                
                Dialog(win) {
                    title = "The Dialog"
                    InsetPane {
                        GridPane {
                            it.numCols = 2
                            
                            Label {
                                it.text = "Number:"
                            },
                            Text {
                                it.onModify.add |e| { validateNumber(e) }
                            },
                            
                            Label {
                                it.text = "Date:"
                            },
                            Text {
                                it.onBlur.add |e| { validateDate(e) }
                            },
                        },
                    },                    
                }.open

            }
        }.open
    }
    
    Void validateNumber(Event e) {
        textWidget := (Text) e.widget
        valid := textWidget.text.isEmpty || textWidget.text.toFloat(false) != null
        textWidget.bg = valid ? null : Color.red
    }

    Void validateDate(Event e) {
        textWidget := (Text) e.widget
        valid := textWidget.text.isEmpty || Date.fromLocale(textWidget.text, "DD MMM YYYY", false) != null
        textWidget.bg = valid ? null : Color.red
    }
}

SlimerDude Tue 25 Oct 2016

Hi Ron,

Thanks for the email, and for clarifying that you're using FWT-JS in a browser.

FWT-JS often takes a little more work and a bit of massaging to get it to work as desired, but often comes up with the goods. In the case of your Validation Demo I've noted the following:

  1. Text widgets need to be repainted() before they update their fg / bg colours.
  2. You can't set their fg / bg colour to null so you must always supply a colour.
  3. onBlur() doesn't seem to work for Text widgets, so use onAction() instead.

My sample demo code now looks like:

using fwt
using gfx
using afIoc
using afDuvet
using afBedSheet
using afBedSheet::Text as BsText

@Js
class Example {
    Void demo() {
        Window {
            win := it
            title = "Validation Demo"
            InsetPane {
                GridPane {
                    it.numCols = 2
                    
                    Label {
                        it.text = "Number:"
                    },
                    Text {
                        it.onModify.add |e| { validateNumber(e) }
                    },
                    
                    Label {
                        it.text = "Date:"
                    },
                    Text {
                        it.onAction.add |e| { validateDate(e) }
                    },
                },
            },
        }.open
    }
    
    Void validateNumber(Event e) {
        textWidget := (Text) e.widget
        valid := textWidget.text.isEmpty || textWidget.text.toFloat(false) != null
        textWidget.bg = valid ? Desktop.sysListBg : Color.red
        textWidget.repaint
    }

    Void validateDate(Event e) {
        textWidget := (Text) e.widget
        valid := textWidget.text.isEmpty || Date.fromLocale(textWidget.text, "DD MMM YYYY", false) != null
        textWidget.bg = valid ? Desktop.sysListBg : Color.red
        textWidget.repaint
    }
}

class IndexPage {
    @Inject HtmlInjector? injector
    BsText render() {
        injector.injectFantomMethod(Example#demo)
        return BsText.fromHtml("<html><head></head><body><h1>Duvet by Alien-Factory</h1></body></html>")
    }
}

const class WebModule {
    @Contribute { serviceType=Routes# }
    static Void contributeRoutes(Configuration conf) {
        conf.add(Route(`/`, IndexPage#render))
    }
}

class Main {
    static Void main(Str[] args) {
        BedSheetBuilder(WebModule#).addModulesFromPod("afDuvet").startWisp(8069, true)
    }
}

Login or Signup to reply.