Merge & Storing input validation logic as a custom property

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

KimD
Posts: 223
Joined: Wed Jul 08, 2015 5:51 am
Location: Wellington, New Zealand

Merge & Storing input validation logic as a custom property

Post by KimD » Tue Apr 16, 2019 11:03 pm

I'm wanting to store the input validation logic for a field, as a custom property of that field.

For example
- Set the MyTestCondition of field "ABC" to Field "ABC" >=5 then return true else return false (mucking around with quote marks abridged)
- If MyTestCondition of field "ABC" then doOption1 else doOption2

I've been trying (unsuccessfully) to achieve this using LC's Merge function. The last sentence in the dictionary entry for Merge sounded very promising - "It also executes any return statements enclosed in "<?" and "?>", and replaces them by the value returned."

I'd appreciate any advice on:

1) Am I going down a sensible path trying to store validation logic as a custom property of a field, or should I just give up and go down the (in the short term MUCH easier) path of storing validation logic in scripts that are activated using the field name?

2) If "Storing validation logic as a custom property is a genius plan" - Am I on a sensible path trying to achieve this using the Merge function, or are there easier ways to achieve the same?

3) If "Merge is the only function that you'll ever need" - Please send me some examples of how I would construct a Merge statement to test the value of a field.

The furthest that I've got so far is -
Put "<? if field " & quote & "ABC" & quote & " >= 5 then return true else return false ?>" into tTest
Answer merge(tTest)
But this is always returning false regardless of the value of field "ABC".

Can <? ?> and [[]] be mixed within a single Merge statement?
This does work - Answer merge("<? if 6 >= 5 then return true else return false ?>")
But this doesn't work - Answer merge("<? if [[4+2]] >= 5 then return true else return false ?>")

Sorry, but, other than a 2008 issue of RevUp, Google has revealed very few examples of LC's merge function.

Thanks in advance

Kim

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 2:07 am

What made you choose the "merge" command in the first place? It is compact and powerful, to be sure, but what made you think it would be a good fit?

Code: Select all

Set the MyTestCondition of field "ABC" to Field "ABC" >=5
So as it reads, this sets the custom property to either true or false, depending on the text in fld "ABC". What beyond that did you want to do? I am not trying to put a damper on anything, but I have always found that simpler is better, more robust, easier to read later, easier to manage, and, er, that may be enough. If you have a "true" in the custom property. do you need a hand in using it later on?

In other words, can you give an example beyond the above where you find yourself with poor tools? Tell me what in the simple line of code above is missing.

The "merge" command is NOT the only thing you need. It may well be, for quite a while, that you do not need it at all. You need the ordinary stuff.

Craig Newman

KimD
Posts: 223
Joined: Wed Jul 08, 2015 5:51 am
Location: Wellington, New Zealand

Re: Merge & Storing input validation logic as a custom property

Post by KimD » Wed Apr 17, 2019 2:54 am

Hi Craig

Thanks for your reply.

What I want to do is store field validation logic in the field (and not in script). To this end - I want to
(1) store the CONDITION component of an IF statement as a custom property of the field. I want to store the text of the condition (e.g. ">=5"), not the result of that test (e.g. "true"); then
(2) evaluate this custom property within an IF statement.

I saw the last sentence of the Merge function dictionary entry and thought "that sounds like what I'm after", but I may have been on entirely the wrong track. I've since seen the Value function and wondered if that would do it. Or maybe Do does it ;-)

Regards

Kim

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 4:20 am

Kim.

They all do something, oftentimes, with a little tweaking, the same thing.

So you want to store ">=5" as a string, but use that later to create a conditional of some kind, that will validate some statement. Try this, just to make sure I see what you mean. On a new card make a button and two fields. In fld 1 put "<=5". In the button script:

Code: Select all

on mouseUp
   put "" into fld 2 --just to see it change
   ask "enter a number" 
   do  "if" && it && field 1 && "then put Higher into fld 2"
end mouseUp
Something like that? And there is no question you could do this with "merge", so I see where you were coming from. :wink:

Craig
Last edited by dunbarx on Wed Apr 17, 2019 4:26 am, edited 1 time in total.

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 4:24 am

In fooling around with Kim's post, I tried this:

Code: Select all

on mouseUp
    put "" into fld 2
   ask "enter a number" 
   
    do  "if" && it && field 1 && "then put Higher into fld 2 else put Lower into fld 2"
end mouseUp
Not much different than the "do" statement in the post above, and it seems that this ought to do what it purports, but instead throws an error. Anyone see where I made a syntax error? I cannot find it.

Craig

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9802
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Merge & Storing input validation logic as a custom property

Post by FourthWorld » Wed Apr 17, 2019 4:27 am

Kim, do you want to run the validation on keyDown, closeField, or something else?

Side note: Merge is so useful in so many contexts that I can appreciate your choice to explore it here. I'm with Craig on this, that this particular exercise isn't the best fit for that. But super kudos for such inventive thinking. Seriously, I wouldn't have thought of merge here, but I can imagine other contexts where it would be useful for ad hoc evaluation of code snippets. Well done.

When we learn how you want to trigger this we can explore a more concise method. But yes, putting formatting parameters in a custom property is an excellent choice here, even if not merge-compatibile specifically. It's akin to CSS attributes, so your thinking is in line with designers of some of the best such systems around.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 4:29 am

Kim.

All this doing and merging is very instructional, and terrific practice at making LC do your bidding.

But I strongly suggest you rethink your methodology. The road you are on is harder than it has to be. How might you simplify your thinking, so you can simplify your coding?

Craig

KimD
Posts: 223
Joined: Wed Jul 08, 2015 5:51 am
Location: Wellington, New Zealand

Re: Merge & Storing input validation logic as a custom property

Post by KimD » Wed Apr 17, 2019 9:02 am

Thanks Craig and Richard.

Yes - the evaluation of the IF statement, which will test the CONDITION that I store as a custom property, is triggered by the user exiting the field.

I'll have another try with this over the next couple of days and get back to you with the results. As you have rightly guessed, part of the reason why I've chosen this approach is to try and teach myself a new aspect of LC. I realise that there are much much easier ways to achieve the same if I store the validation logic in script instead of as a custom property.

Regards

Kim

AxWald
Posts: 578
Joined: Thu Mar 06, 2014 2:57 pm

Re: Merge & Storing input validation logic as a custom property

Post by AxWald » Wed Apr 17, 2019 2:00 pm

Hi,

try this:
  1. Choose your field, give it a custom property "cCondition".
  2. Put a condition in, here as a simple example:

    Code: Select all

    is a number
  3. Put the evaluation code into the field script:

    Code: Select all

    on closeField
       if the controlkey is down then \
             exit closeField                     --  just for safety, to avoid modal loops ...
       focus on fld "next_fld"                   --  Important: Move the focus away from this field!
       
       do "get " & (me && the cCondition of me)  --  Evaluate the condition
       if it then                                --  Condition met:
          wait 0 with messages                       --   = "Do nothing!"
          --  answer "Condition met!"                --  or say something ...
       else                                      --  Condition not met:
          answer "Condition not met!"                --  Complain!
       end if
       pass closeField
    end closeField
  4. Enjoy! Each time a new wrong value is entered the field complains! :)
Remarks:
  1. You want to use "closeField", that's sent when the user leaves the field AND its content has changed.
    Beware not to create a "modal loop" where you have one answer box after the other - thus we focus out (to the next field in the UI) at the beginning of the handler.
    .
  2. It's quite useful to have a placeholder in cCondition. This allows for more sophisticated conditions:

    Code: Select all

    ([[me]] is a number) and ([[me]] > 0) and ([[me]] < 100)
    (We want a numeric value between 1 and 99 in the field. The fields content is, seen from the field script, simply "me". Then we add double square brackets (= "[[me]]") so we can use it conveniently in merge())

    For sure, you'll have to change the field script - replace these 2 lines:

    Code: Select all

       do "get " & (me && the cCondition of me)  --  Evaluate the condition
       if it then                                --  Condition met:
    with:

    Code: Select all

       if merge("[[" & merge(the cCondition of me) & "]]") then  --  Test it:
    We greatly enhanced the capabilities of our script, even found reason to use "merge", and, best of all, saved 1 precious line of code ;-)))
    .
  3. I'm using merge here in 2 ways - the inner merge replaces the placeholders, the outer merge evaluates the resulting expression. Regarding the "<? ?>" notation, I searched & tested, but found nothing I could really comprehend. Anybody cares explaining?
Have fun!
All code published by me here was created with Community Editions of LC (thus is GPLv3).
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 2:46 pm

If you are exploring the sort of thing Axwald presented, to exercise LC for fun and profit, then go for it.

Otherwise I still suggest, and this also will exercise LC, to do what you intend differently. You call this "storing the validation logic in a script". I call it rethinking.

In other words, what is the advantage of storing an expression, and then building another expression that incorporates the first one? All this to test a certain condition. Why not just use an expression? And yes, all that would live in a handler, though values, not conditionals, might well live in a custom property.

Can you give an example, perhaps in pseudoCode, where your current idea is better?

Craig

AxWald
Posts: 578
Joined: Thu Mar 06, 2014 2:57 pm

Re: Merge & Storing input validation logic as a custom property

Post by AxWald » Wed Apr 17, 2019 5:43 pm

Hi,
dunbarx wrote:
Wed Apr 17, 2019 2:46 pm
[...] what is the advantage of storing an expression, and then building another expression that incorporates the first one?
I just recently (while refactoring) moved all my SQL strings into custom properties. And use them now with a system similar to the one described.

Reason: Too often I had to roll out an update when only one slightly different SQL string was required.
(I'm writing database frontends that basically do what a CRM can do too, just my solutions live besides such one, and vastly extend & improve its often limited & bothersome capabilities. So my typical project contains 1 standalone (acts mainly as main menu), and a varying number of "module stacks" that each has its own task. And most these tasks is done displaying data from a db, modifying it, and writing it back. Mucho SQL!)

Solution: There's now a tiny section in my startup process that looks for a certain file "[ApplicationName].cPrp". If such exists, it reads the first 3 bytes of it, and when these are not a special signature (meaning "done already" ...), reads all, decrypts it, decodes the contained nested array & overwrites all the cProps of all the stacks that have entries within, and saves the affected stacks.
Finally, it writes the data back to the file, with the above mentioned 3 byte signature for "done already" in front. So that it doesn't do the same again at next startup.
That's a very easy thing & runs w/o any noticeable startup time penalty.

Now I can, if required, email such a file to a special user for a quick field test. Or I can have now identical stacks for different customers, with different databases.

Bonus: I wrote a tool to handle this, and to create the "[ApplicationName].cPrp's. Since I have all my SQL-containing cProps named wisely I can now quickly create a file with all SQL strings in all stacks in a whole project folder.
This I can save as a plaintext file (and import again) too - so now I can quickly find where the hell I have used this field, or that other. Or where I call this stored procedure, or that view that I'm about to change.
With search & replace. Without having to run a full grep over all the project & editing each single stack ...


This stuff is, in my view, not exactly "programmatic logic", it's just strings that are prone to change.
Like Kim's condition statement, like text strings shown in error messages that may need to be localized one day, like version numbers etc.

Having these hardcoded doesn't save me much work while developing, if any - but it has a heavy cost in the maintenance of a larger project.
Back in the good old days I'd have saved such stuff in the resource fork of my stacks, but since such got steved, well, cProps are a nice replacement.

Have fun!
All code published by me here was created with Community Editions of LC (thus is GPLv3).
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 5:47 pm

Kim.

Axwald has made a case, and nicely. Let us know how you get on...

Craig

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9802
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Merge & Storing input validation logic as a custom property

Post by FourthWorld » Wed Apr 17, 2019 6:40 pm

dunbarx wrote:
Wed Apr 17, 2019 2:46 pm
...what is the advantage of storing an expression, and then building another expression that incorporates the first one?
Generalization.

With form input validation specifically, consider the beautifully simple way HTML handles such things:

Code: Select all

 <input type="number" name="quantity" min="1" max="5">
(See other validation types at https://www.w3schools.com/htmL/html_form_attributes.asp )

With a library checking closefield and possibly other messages, it wouldn't be too hard to have delishiously sparse custom property values defining at least the range of evaluations HTML supports.

For example, if the library sees the existence of custom properties valChecker["min"] and valChecker["max"] it would know to limit inputs to only numbers within that range, and dispatch a message to the target if outside that range so the target object can take whatever action might be appropriate for its context.

For any object not containing a valChecker property set the closeField message would just be passed, so it would have no adverse effect on anything else.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9579
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Merge & Storing input validation logic as a custom property

Post by dunbarx » Wed Apr 17, 2019 7:15 pm

Kim.

Lots of stuff.

I still would love to see a (OK if pseudo) typical case that you want to validate. Then we can fool around with various solutions and methods.

Craig

KimD
Posts: 223
Joined: Wed Jul 08, 2015 5:51 am
Location: Wellington, New Zealand

Re: Merge & Storing input validation logic as a custom property

Post by KimD » Wed Apr 17, 2019 10:27 pm

Thanks all

To answer your questions about "why". I'm building an e-forms app (for my first paying client). Up until a week ago all of my data validation only considered the single field being entered.
1) I stored validation logic in as a custom property of the field. For example -
Set the ValRule1 of this field to "GreaterThanOrEqualTo,5"
2) Then I have a repeat loop handler, triggered by exit field
Repeat for each xRule in the ValRule1 of this field
Switch item 1 of xRule
Case "GreaterThanOrEqualTo"
If this field >= item 2 of xRule then
etc

It all worked fine, it was nicely self documenting, and it was easy to maintain, and if I copied and renamed a field then I didn't need to do anything to get the input validation working. Then a week ago my client came up with a requirement to validate field A based on the contents of field B. Of course they did. It would have taken me 10 minutes to write this as a handler, but I like my "store validation logic as a custom property of the field" model, so I thought that I'd put the effort into incorporating this new requirement into my existing CP based model. At first I looked at storing the name of field B, the break points for field B values, the break points for Field A values; all as items in my Custom property. It would have been a bit ugly, but I could probably have implemented this variant in 30 minutes.

Then I thought - "If LC could store the CONDITION part of an IF statement as a custom property, then I'd have a very flexible nicely self documenting implementation". And the next thing that I knew I was down the "storing code as data" rabbit hole.

I'm justifying this on the basis of (1) it's future proofing, and (2) Its a good LC learning experience; but the next thing after this on my to-do list after this is "deploy to Apple", and I've never enjoyed wading through the Apple treakle, so can probably add (3) Postpone the task that I'm not looking forward to ;-)

My actual need is - If field A = 90 and field B > 0 then "Fail" else "Pass"
It's a validation of a latitude, where the user has the option of entering the latitude as either decimal degrees or degrees & minutes. This will trigger on exiting either Field A or Field B (the trigger handler is already written / working). So the part that I want to store as a Custom Property is "field A = 90 and field B > 0".

Regards

Kim

Post Reply

Return to “Getting Started with LiveCode - Complete Beginners”