Hi there AppWorks fans,
Welcome to a new installment of AppWorks tips.
We, as low-code developers and analysts always run ahead on the features to implement. Sometimes with a static result, but there are end-users (or “knowledge workers”) that want to have more control on what information is saved on an entity. Specially for these users, we implement a feature where these users can add their own properties to an entity instance. To give a little control on what is eventually saved in the AppWorks database, we provide the administrators the possibility to configure custom-type of properties to select from. Keep on reading as I see this type of implementation in almost every project, but this post moves it to a new level!
Let get right into it…
I start clean, with an empty VM, clean workspace, and clean project. The first thing I do with my
awdev account is creating a new administration entity with the name
custom_prop. You can use this table for the input on the different properties to add:
|Type||cp_type||Text||Length 64; as in a description; like e-mail, or passport, color, document|
|Default||cp_default||Text||Length 1024; anything can be in here…also comma separated “list” data!|
|Is read only||cp_is_read_only||Boolean|
|Kind||cp_kind||EnumText (static)||Length 16; [“text” (default), “boolean”, “date”, “date_time”, “number”, “list”]|
|RegEx||cp_regex||Text||Length 512; can be a length-check, or other specific checks on e-mail, or color codes|
Generate all the other BBs and make these additional changes:
lyt_default(just a naming convention from my side!)
Custom properties, and apply it with category
- Edit the entity properties with a display name
Custom propertyand name
- Remove the ‘None’ option from the boolean type of fields
- Expand the ‘Text’ type of fields to the correct length…Like in the notes of the table above
- Add the static enumeration values as described in the notes; You can remove the ‘none’ option from the list
Our first publication will be something like this:
Where the ‘Create’ form looks like this:
In runtime, we can now create our own type of properties; Like this example set:
|Type||Default||Is read only||Is required||Kind||RegEx|
|‘leading zero number’||
|‘yes / no’||
|‘date format (mm/dd/yyyy)’||
|‘datetime format (yyyy-mm-dd hh:mm:ss)’||
Yes, the default value for the “colors” list-example indeed contains an extra comma…The regex took me too long to figure out! 😅
Evaluate your regular expressions here
Now what? We have the administration part ready, let’s make sure we consume from it. We make it really simple; just create a ‘Case’ entity with a simple ‘Name’, and ‘Subject’ property; Generate all the other stuff…You know the drill by now! On the new ‘Case’ entity, we create a new ‘hasChild’ relation to a new entity named
property. You can now open this new entity which will we give a
prop_value property with again the default BBs applied; renamed to your own needs. I also make sure the
lst_properties is not available in runtime (as it’s only for internal use within our case!):
Next step is adding a ‘toOne’ relation from this ‘Property’ entity to the ‘Custom Prop’ entity (I named it
to_one_custom_prop). With this update, we can now also add this relation to the ‘Create’ form of our ‘Property’ entity. Like this:
You can make it required as well! Also, make sure to disable the ‘Create’ action in the bottom…It fell of my screenshot!
We move back to our ‘Case’ entity as we want to make sure we can create our new ‘Property’ instances on it. For this, I create a new ‘Form’ BB with name
CreateProperties on the ‘Case’ entity, and I add my ‘hasChild’ relation onto it; Make sure to convert it to a ‘Grid’ and add the additional properties we would like to see. In my case the
prop_value and the related ‘toOne’
cp_type property…Are you still with me? So, like this:
At the bottom of that right panel (It fell of the screenshot again!), you can make sure to only ‘Create’ and ‘Delete’ new properties. You can even make sure the creation happens in a modal popup, instead of inline of the grid. Have a double-check yourself!
The last thing we miss now (for our first try-out), is adding this new form in the layout of the ‘Case’ entity. So, open that
lyt_default BB, add a second ‘Form’ panel next to the existing one and select the new form
CreateProperties. Like this:
Now it’s time for a publication and to have a check in runtime for a newly created ‘Case’ entity…
NICEEEEE!! What’s next? Well, first a coffee break! ☕
Have you tried creating any additional properties yet? I hope you have; I also hope you make the conclusion that the value you fill in doesn’t matter! Correct!? Well, that value is exactly what we would like to validate on. So, the value for our property must match the criteria we configured for that custom property…You’re still with me here? So, when I create a new additional property of config type ‘e-mail’ it must be validated to the regex behind that configuration! How on earth!? Well, watch and learn…
We’re talking about ‘Rule’ BBs (of different events) here…Let’s start simple and make sure that when our property type selection changes (in other words; Our relation to the custom property changes!), we want to grab the default value of the configuration property and fill it in. Simple, but efficient like this
e_onrelchange_set_default ‘Rule’ BB (on the ‘hasChild’ ‘Property’ entity):
Publish, and evaluate it…It should work for you as well!
Next step is about validation; So, when the property value changes it must be validated against 3 things:
- If it’s required; so, it must have a value at that moment
- If it’s read only; a bit harder to implement, but it means you can’t change it once the value is created
- If the value is in place, it should meet the regular expression…That’s where it gets interesting! 😎
The first one is easy…Just a new ‘onCreate’ event with name
e_oncreate_is_required with this implementation:
This is the advanced view behind it:
item.Properties.prop_value is null && item.to_one_custom_prop.Properties.cp_is_required==true
I also apply a second ‘Rule’ BB
e_onpropchange_is_required like this:
Why? Well, this first one is during the creation phase of the property; The other, when changing the value afterward!
Read here all about the
Identity.ItemStatuscheck you see in the screenshot…It all has a reason!
Could we do it with one onchange ‘Rule’ BB? Sure, but would it behave like our implementation!? I don’t think so!
Let’s continue…The second one making it read only…
For this one we make a rather nasty workaround with a “helper” property named
prop_value_old. We don’t show this property, but we fill its value via an ‘onCreate’ Rule BB with the current value (a task for yourself!). After this, we can check this value with the current value like this ‘onChange’ Rule BB named
The ‘Disable’ action is always hard to understand; In dummy talk: When our old value and current value are equal, we disable the field…You would normally think the other way around; So, when those field values are NOT equal to each other, we leave the field enabled! #ItIsWhatItIs.
Does it work?…Ohw YEAH! 🤗
Finally, the third one…The RegEx check! The fun part of this post…As how on earth will we check a regular expression out of the box!? Watch and learn my friend as we make the impossible, possible!…What a nasty aftertaste! 😱
Create a new ‘Rule’ BB (or make a copy from
e_oncreate_is_required) and name it
e_oncreate_matches_regex. Open it and have a low-code implementation like this:
WHAT? REALLY? That simple? Yes, my friend…that easy! I was also a bit amazed!? Watch out for the extra exclamation mark at the front which flips the expression; So, when it NOT matches, show the error…
For you to copy:
Does it work? YESSSS, it works…smoothly! 😁
Once created, we can update our value as well which also needs to validate again to my regular expression! Well, I created a new ‘Rule’ BB
e_onpropchange_matches_regex with a condition like this:
(! item.Properties.prop_value.matches(item.to_one_custom_prop.Properties.cp_regex)) && item.Identity.ItemStatus==1…Guess what? It’s NOT working!?!?
WHAT?…I extended it to this:
Now I only get errors for the ‘e-mail’ types, so that’s OK! To double-check if I’m doing something wrong here, I moved to this:
So, I hardcoded the regex…That solves the problem, but my conclusion is that we found a bug here as my related property is not resolved to an expected string result!
It’s getting even more interesting; watch what happens when I output the regex itself in the error message:
Now, all of a sudden; 2 are correct!?!? #SUPPORT? In the meanwhile, you can use a workaround like this?:
Not nice at all; it’s hardcoded; AND…It doesn’t even get the expected result…Strange! During property creation it all went so smooth…Or is it just my regex skills that need an upgrade!? I don’t know…Maybe it has to do with the escape character
\ as well? Comment me as I saw enough now! I simply made sure the values are never editable after they’re created. My users just need to remove it and add a new one! 😏
Just for you to note: the ‘matches()’ follows the principles from Java, but you have some examples already now from this post!
Great, what a rush, what a “DONE”…It went sooo smoothly, but we eventually hit that concrete wall again! It hurts, but we’ll just continue with our workaround which still makes our end-users happy! We learned a lot here when it comes to adding your own custom properties to an entity directly in runtime. Regular expressions passed our knowledge, configuring things in runtime is always interesting to gain knowledge from, and we saw some workarounds with “helper” properties with nicely crafted ‘Rule’ BBs. I leave it for now…Have a good weekend and I see you in the next post.