How do I create a custom form?

Oh I see what you meant by left branch now. Hmm…

1 Like

Here is a version where I use trim whitespace and lowercase text to build the relation that checks for duplicates. Also using trim on submit in the add row action…

6 Likes

Hi @Darren_Murphy
I’ve already mentioned this post on several other posts with appreciation but I’d like to extend another “thank you” also here.
On the topic of duplicates, I’d like to ask a couple of questions:

  1. As it seems, the custom form is NOT creating a new line when form is opened. Instead, the form is “riding” on the top line of whichever table we’re in. Is that correct?
  2. Assuming the above is correct, and all input/form columns are USC, it seems that indeed we’re safe from duplicates. However, one challenge with this “top line” usage. What happens if one of the columns is a counter and as part of the “save” button actions we increment it by 1? Won’t this potentially allow same counter for several concurrent form submissions? Any other problems this may create?
    image
  3. Even if duplicates aren’t possible as per point 2 above, I have another “stupid” issue that I cannot figure out. I’m sure it’s SUPER simple.
    it seems we’ll always have the same counter twice. Once for the last entry (created at the bottom of the table) and once in the first row. I also tried to use a math column with “+1” but that didn’t seem to solve anything. Any ideas for a counter inside custom forms?
  4. SUPER simple again: These clients numbers should be, ideally, consecutive no matter which user entered the last entry via the custom form. Won’t that create different set of numbers for each user?

Thanks again!

That’s generally the case, but it depends how you got there. For example, if you were in the details screen of a record 20 or 30 rows deep, then did a Show New Screen → This Item from there, then that’s the row where your User Specific Column values will go. What I’ll often do is open my custom form on top of a completely separate table - a table that has just a single row. Then collect all my form data in that row, before writing a new row to the destination table when the user submits. This keeps things nice and clean.

What’s the purpose of this counter? Sounds like it has nothing to do with the custom form?

Again, I think I need to understand better what you’re using this counter for…

So you’re wanting some sort of unique incrementing number?
A word of warning… down this path there be dragons :wink:

Have a read through this thread… (all of it)

2 Likes

Thanks!
A very detailed answer, as always. You’re right, the counter is a sequential client number, added to each lead (even before they’re a client, if at all). This will naturally create a situation in which two clients won’t have sequential numbers, even if they have been created one after a another (if a lead was created in between it’ll take that consecutive number). What I’ve done in the past is use the LockService on Google Script. It seems to be exactly what it is meant for, but it’s not very fast and it can create lags if we have many submissions at once, all asking the locked part of the script to generate a number for a new lead. I was really hoping to replace this (hardcore?) lock with a more elegant solution from Glide.

I’ve read all of the posts in the topic you linked and it seems that indeed these dragons hunt many of us :slight_smile:
I very much liked your video example.
However, I’m still puzzled by the race condition. Have you ever received feedback from Glide about this?
Same question, different approach, have you ever found out a way to force an action to be on the server-side? Specifically, having the compound action of “incremate” happen on the server. This will, hopefully, complete remove any chance of a race condition, even if two forms are submitted at the exact same time.
I very much liked your idea of having a separate table for the custom form, as well as the column that has the same value in all rows (next number), inside the data table. Again, this one-row custom form table isn’t immune to the race condition. Or is it?

Thank you :slight_smile:

No, not really. But concurrency can definitely be a problem, and I’ve bumped into its effects several times.

My goto solution these days for dealing with race conditions/concurrency is to delegate to Integromat. By funnelling critical updates through Integromat I’m able to ensure that they are queued and handled serially, and avoid users tripping over each other or clobbering each other’s updates.

Below is some more reading on this topic, where I described an option for a specific use case:

No, it’s not. As far as I’m aware, the only way to ensure immunity is to delegate updates to a 3rd party.

3 Likes

Thanks again.
Integromat, or any 3rd party call, will again create these lags when you have multiple concurrent requests for such a “protected counter”.
No way of doing it inside Glide without risk of concurrency?


Edit:
I just remembered the interval limitation…


As this number is used rather often (for each new lead), it’ll most definitely happen concurrently. Integromat will accept the trigger, but surely delay its response, thus creating a lag.

I guess it depends on your use case, and how quickly you need the result. My most recent use case is as follows:

  • Twice a day, I have about 200 users that the submit a result of a “test”
  • They all do it within about a 1-2 hour timespan
  • As each user submits, their UserID is added to a list of users that have submitted
  • The end result is a single joined list of ~200 user IDs.

When I first implemented this, it was all done within Glide. Each users ID was added to the list as they submitted and a new list was written, replacing the existing list. On the very first day, I had several users complaining that they had submitted, but their name didn’t appear on the list. It didn’t take me long to figure out what was happening. Concurrency. If 2 users happened to submit at the same time, then the last one in would win, and the first users ID would get bumped from the list. The answer was Integromat, and I changed my flow as follows:

  • Now as each user submits, a webhook is sent with their UserID and the TestID
  • Integromat checks the backend sheet to find the correct TestID row, and adds their ID to the list.
  • If two or more users submit at the same time, it doesn’t matter as the requests are queued.

Since I’ve implemented the above, it’s worked perfectly and there have been zero complaints. So again, it depends on your use case. If you need instant results, then no it’s not a good solution. But if you can live with a slight delay, then I think it’s the most reliable solution available at the moment.

1 Like

Thanks!
I’ve found a nice little API which might help, but I’m again concerned about concurrency and speed.
The API is name Newton.
For our super-simple use of incrementing a number:
1.

https://newton.now.sh/api/v2/simplify/LN%2B1

PS - This URL is created with a template column within Glide as the Construct URL column seems like an overkill.
image

Using the API column to reach the API
image

The result is fine
image

Now I’m at a roadblock as to the best way to extract the number after “result”.

First, what do you think about this solution?
Second, any suggestion as to how to extract the result?

PS - I’m finding it super hard to believe that we need 3rd parties just to avoid concurrency for such a simple task. This should be handled within Glide.

I think you can input .result in your JQ Query to just get the result.

you’re good! :slight_smile:
Documentation isn’t Glide’s strong suit. So many great features but no explanation as to how to use them. Good thing we have this wonderful community.
While I have you, any ideas on how to increment a number within glide, avoiding concurrency for a mission-critical counter?

I just noticed something, but I might be wrong.
Is the API column calculated every time the sheet is updated?
If so, it’s VERY bad for a fixed number (such as client number).
Even if we “set value” using an component action, we’re still (again) at risk of having the two or more concurrent actions happening together :frowning:
Are we really forced into LockService on Google Apps Script?

HI
Could you please share some more information about how this is done?
I seem to be struggling with the “parent” table instead of a single-row table as you suggest (which I already created, as a Glide Table and not Gsheet).

Perhaps possible to apply an example here?

What you mean is that instead of adding a New Row to animals, you’ll start a new screen point to this single-row table. But, then what? Every other action will still point back to the animals table.
image

Thanks!

hmm, I need to update that app. I wouldn’t do that action like that now. The else there is completely un-necessary, and I probably wouldn’t have that extra Set Columns action in there.

It’s late here, but try to find some time to have a look tomorrow.

I don’t believe the intervals apply to webhook modules with their triggers set to ‘instant’.

My experience.

They put a video on JQ Query in the plugins page, if that’s what you need.

2 Likes

Thanks @ThinhDinh. That’s not quite what I was aiming for but surely helpful!

BTW - Strange, but it seems the search doesn’t cover the Plugins, which is why I didn’t see this before

Thanks @Darren_Murphy. Another issue that I’ve noticed (or shall I say another thing I’m doing wrong): When we use the “Show new screen” action it works only once per each app screen. If we put another button, asking for a new screen from it, we’ll get a generic Glide details page. Surely I’m doing something wrong, which is why you guys save me each time :slight_smile:


Edit:
My bad about the single screen issue. I simply configured the action wrong. I forgot that each new screen has to point to “this item”, which allows us to manipulate as needed. It seems like a rather strange, not to say aggressive, workaround in the sense that we need to demolish some/all connection to “this item” in order to have the freedom to create our customs forms.

It works on the main Glide website (http://glideapps.com/), I assume since the documentations is on a subdomain (https://docs.glideapps.com/) they do not cover those.

I like the concept of your template to check for duplicates. But I was able to EDIT and change Tigers to Tiger, and it didn’t catch the DUPE, then. Personally, I would not allow edit on a field that had to be NO DUPES ALLOWED and we had already checked it for that.

I’m also not following what all the empty entries in the database are for. Are they all simply temporary edit rows that got left behind? I’m impressed at the work that went into this template app.

I appreciate the implementation of calculated string columns (lower, trim, etc).

I think to fully understand all the concepts I will have to create my own template.