Home   Archive   Permalink



Displaying an error message at the end of a field and making it disappear

Hi. I'm wondering if you know of a generic method to display errors at the end of a field using the at method or something and computing the field/offset and field/size plus a little space more to offset the error message. Preferably, I'd like to flag several fields and place their errors at the end of the field, then removing them when the field is entered. Here is my code
R E B O L []
do %play.r
beep: load %err.wav
    
fields:[
vi to-integer "r" "Id"
vn "" "r" "Name"
vdc to-decimal "r" "Decimal"
vdt to-date "r" "Date"
vtm to-time "r" "Time"
vmn to-money "r" "Money"
]
    
errchk: func [fields errors ][
    i: 0
    foreach [fld tp req nm ] fields [
        f: get fld
        print f/text
        print req
        print nm
        if req == "r" [
            if f/text == "" [i: i + 1 errors/:i/1: fld errors/:i/2: join to-string nm " Is a Required Field"]
                ]
        if tp <> "" [
            if error? try [ do rejoin [tp " " f/text]] [i: i + 1 errors/:i/1: fld errors/:i/2: join to-string nm " Invalid Data"]
        ]
    ]
]
view gui: layout[
text "id"    vi: field
text "name"    vn: field
text "decimal"    vdc: field
text "date"    vdt: field
text "time"    vtm: field
text "money"    vmn: field
    
    button "val" [
        errors: array [12 2] copy []
        errchk fields errors
        either errors/1/1 == none [
            alert "Good Entry"
        ][
            alert reform ["Error- " errors/1/2]
            ;at vdc/offset + vdc/size + 2 show error for field
            focus get errors/1/1
            play beep
            show gui
            return
        ]
    ]
]


posted by:   John     1-May-2014/13:49:14-7:00



I have to thank you for this example. That "code is data" concept of REBOL makes it possible to do some interesting things. How about this as a possible solution:
    
R E B O L []
;do %play.r
;beep: load %err.wav
        
fields:[
vi to-integer "r" "Id" vi-err
vn "" "r" "Name" vn-err
vdc to-decimal "r" "Decimal" vdc-err
vdt to-date "r" "Date" vdt-err
vtm to-time "r" "Time" vtm-err
vmn to-money "r" "Money" vmn-err
]
        
errchk: func [fields errors ][
     i: 0
     foreach [fld tp req nm errmsg] fields [
         set-face get errmsg "" ;; This clears previous message    
         f: get fld
         print f/text
         print req
         print nm
         if req == "r" [
             if f/text == "" [
                 i: i + 1
                 errors/:i/1: fld
                 errors/:i/2: join to-string nm " Is a Required Field"
                 errtxt: copy ""
                 errtxt: rejoin [nm " is required"]
                 set-face get errmsg errtxt ;; This puts error message by field
             ]
         ]
         if tp <> "" [
             if error? try [ do rejoin [tp " " f/text]] [
                 i: i + 1
                 errors/:i/1: fld
                 errors/:i/2: join to-string nm " Invalid Data"
                 errtxt: copy ""
                 errtxt: rejoin [nm " is invalid"]
                 set-face get errmsg errtxt ;; This puts error message by field
             ]
         ]
     ]
]
    
view gui: layout[
     across
     text "id"
     return
     vi: field vi-err: text 150 ""
     return
     text "name"
     return
     vn: field vn-err: text 150 ""
     return
     text "decimal"
     return
     vdc: field vdc-err: text 150 ""
     return
     text "date"
     return
     vdt: field vdt-err: text 150 ""
     return
     text "time"
     return
     vtm: field vtm-err: text 150 ""
     return
     text "money"
     return
     vmn: field vmn-err: text 150 ""
     return
     button "val" [
         errors: array [12 2] copy []
         errchk fields errors
         either errors/1/1 == none [
             alert "Good Entry"
         ][
             alert "Fix marked items"
;;         alert reform ["Error- " errors/1/2]
;;         ;at vdc/offset + vdc/size + 2 show error for field
;;         focus get errors/1/1
;;         play beep
;;         show gui
;;         return
         ]
     ]
     button 200 "Halt for debugging" [halt]
]
    


posted by:   Steven White     2-May-2014/11:51:17-7:00



Hi Steve,
    
Thanks for your input on this. Putting the fields at the end of input fields is one way to do this. I was hoping for something more generic and that can be overlaid with other columns of data where the error messages are appearing now. Perhaps a panel is the way to do it. If it has errors then swap in the error panel, otherwise swap in the normal fields that go there. Actually, I looked at Carl's spreadsheet program since he seems to be able to create columns out of thin air that are not specifically declared in the layout design at inception. The program is pretty high level for me and I can't understand what he is doing at this point. I will keep working on this area for a bit. You are very right about the power of rebol to mix both data and program code. I intend to add another layer of code where I will put in ad hoc tests for some or all of the fields that is actual rebol code that I will execute and test and supply an error message for. This will appear in the "fields" parameters that I give at the beginning of the program then will be one of the items I do a foreach loop on.

posted by:   john     2-May-2014/13:27:26-7:00



"The program is pretty high level for me and I can't understand what he is doing at this point."
    
I'm glad to see it is not just me. That is one of my complaints about the REBOL environment. Carl's examples show what can be done, and maybe they are examples of the ultimate REBOL coding, the way things really should be, true REBOL mastery demonstrated by The Founder, BUT, something more is needed for those of us several levels below that. I think that a lot of programming genius is lost or under-appreciated because of lack of documentation.    
    
Maybe it's like religion. We have Carl at the top showing us the ultimate goal. Below that we have "disciples" interpreting the teachings from the top. Those would be people like Nick with his business programming documentation. Then we have the rest of us, trying to apply the interpretations of the teachings to our daily lives. Maybe the "Red" programming project is like the Lutherans.    
    
Anyway, I was thinking about your project at lunch and wondering why you would need a generic scheme for error message placement when you do not have a generic scheme for the data field placement. If the locations of the fields are fixed, why not fix the locations of the error messages. It's fun to work it out of course, and instructive.    
    
You can use the "at" keyword to specify exactly where some item is placed. You might have to use the layout/tight function to gain close control of item placement. You could locate error messages right on top of data fields. Then, for normal data entry, you would "show" the data entry fields and "hide" the error messages. When you encounter an error, load up the text of the error message and show it, while hiding the data entry field that occupies the same place. I have done something like this for a small demo of a different project.    
    
Or, since you build an array of error message in "errors," you could open a second window or a second instance of REBOL (with "launch) to show all errors at one time. A person could have the error window beside the data window and go down the list of things to fix.    
    
Or, you could flag bad fields by changing their color, and then put the detailed error message under a right-click of the data field somehow.
    
That's about the limit of my REBOL skill at this time. I have been using it off and on for a decade or more and still don't quite get it. But it is coming.

posted by:   Steven White     2-May-2014/14:59:38-7:00



Here is a temporary solution to the display of the error message at the point of error. I would like the change the icon to a left pointing arrow and instead of a timeout I would like to go directly to the focus on the field instead of waiting on the request box to timeout. Maybe I could just display multiple errors in a scrollable status bar at the bottom of the screen. This is not a terribly important problem but it continues to improve my skills at rebol trying to solve it.
R E B O L []
do %play.r
beep: load %err.wav
;vii: array [6] copy ["*"]
    
fields:[
vi to-integer "r" "Id"
    
vn "" "r" "Name"
vdc to-decimal "r" "Decimal"
vdt to-date "r" "Date"
vtm to-time "r" "Time"
vmn to-money "r" "Money"
]
    
errchk: func [fields errors ][
    i: 0
    foreach [fld tp req nm ] fields [
        f: get fld
        if req == "r" [
            if f/text == "" [i: i + 1 errors/:i/1: fld errors/:i/2: join to-string nm " Is a Required Field"]
        ]
        if tp <> "" [
            if error? try [ do rejoin [tp " " f/text]] [i: i + 1 errors/:i/1: fld errors/:i/2: join to-string nm " Invalid Data"]
        ]
    ]
]
view gui: layout[
    
size 500x500
    
text "id" vi: field
    
text "name" vn: field
text "decimal" vdc: field
text "date" vdt: field
text "time" vtm: field
text "money" vmn: field
    
button "val" [
        errors: array [12 2] copy []
        errchk fields errors
        either errors/1/1 == none [
            alert "Good Entry"
        ][
            play beep    
            f: get errors/1/1
            focus f
            request/only/offset/timeout reform ["Error- " errors/1/2] f/offset + f/size + 60x0 2.5
            show gui
            return
        ]
    ]
]

posted by:   John     2-May-2014/17:05:50-7:00



Hi Steven,
Thanks again for those ideas. I think putting the error messages in a scrollable area at the bottom or in popup is probably good. These are less important concerns but they are helpful in acquiring skill. It's funny that Carl describes his spreadsheet program as "beginner" level code. I remember when I was rock climbing experts would classify climbs as beginner level 5.0 climbs when I had been climbing for a year or 2 and they seemed way harder than that. People who can write compilers probably do consider the spreadsheet code to be low level. :)


posted by:   John     2-May-2014/17:19:37-7:00



John,
    
Do you simply want to include the error in the text inside the field, or do you want a separate widget to be displayed? You could add the text using some variation of this string padding function that I use often in prettifying text formatting:
    
padspaces: func [inpt digits /front /local strng] [
     strng: copy/part form inpt digits
     either front [
         insert/dup head strng " " (digits - (length? strng))
     ] [
         insert/dup tail strng " " (digits - (length? strng))
     ]
     head strng
]

posted by:   Nick     3-May-2014/11:00:26-7:00



Apply that function to the text in each field, then append your error message (so each error message appears at the same position in every field). To remove the error message, 'copy/part the field text to the padding length.

posted by:   Nick     4-May-2014/3:24:11-7:00