Mar 02, 2020 08:20 PM
Um, yeah - it is. But first, a little of the backstory.
As is often the case just when you’ve thought you’ve seen it all, a client asks -
Is it possible to chain blocks and run them sequentially - as one completes, the next one starts?
No, right?
But then she tossed in another requirement -
The computational results from the first block must be available to the next block and sometimes to all subsequent blocks.
Oy! Nothing like a mind-bender for a Monday morning.
This business requirement is daunting – indeed, impossible given the nature of Script Blocks. I’m sure the Airtable folks have pondered this, but as it stands, it’s off the table for now, right? Indeed, Script Blocks are simply not capable … until and unless … you factor in the amazing power of that which Airtable is known and most famous for - simple data/content management with an intimate relationship with integrated script.
Often, it is the alchemy of data and code that spark the most remote possibilities into a new reality.
Simple Workflow Example - a Happiness Survey
Imagine a three-step process asking basic questions about your day. It’s a survey per-se and I’ve embodied the essence of it into a simple table shown below. Each step has a question and a column for answers. Lastly, there’s a final step - Happiness Assessment - that computes your relative happiness based on your answers
The following screenshot shows this three-step process but also displays a very important field showing Block Script in a long text field.
As I mentioned, each step is a question, and each question is presented abstractly in the script using the value in the first column (i.e., Process Step). The final stage in the process is based upon the answers at each step in the survey process.
BlockChaining
To do this elegantly and well, chaining together different script blocks is ideal.
Each script in each process is loaded and executed sequentially. A single “runner” Block orchestrates the execution of each data-based block and it manages the in-memory scope of the results from start to finish.
The final step includes the block shown below which displays the resulting happiness assessment. Note the reference to aRecords
- this is the variable that contains all of the answers gathered from each of the chained blocks.
And the outcome in the block runner reveals this display when all four steps have completed.
Summary
Block chaining is possible. In and of itself, this is an important realization. While my example is super simple and somewhat lame, imagine the incredible solutions that could be built by chaining block scripts together in easily-managed table data.
As I mentioned, it is also possible to manage, share, and aggregate computational results that occur across multiple block segments.
Tell me - is Block Chaining a thing?
Jun 26, 2020 04:12 AM
Imagine you’re running multiple script fragments from a list of records and in that process you need to summarize the outcomes of each fragment’s choices (button 1, button 2, etc.). Now imagine you need a global variable that sustains those choices made as each fragment is executed. Lastly, imagine a requirement where the final script fragment being executed needs to know the choices made by all the other script fragments executed by the eval() method.
You need a global variable that can sustain the outcomes across all script evaluations and such that this variable is known and accessible inside each script fragment evaluation. That is the purpose of aRecords (i.e. answer records).
Feel free to find other ways to meet these requirements with a different design, but it’s likely this design is a good one.
Mke sense?
Jun 26, 2020 06:17 AM
Thanks a lot @Bill.French,
I’ll read to you with all due attention after my work.
Yes, it could always happen if I experiment in order to learn, but be sure that I had no second thoughts of thinking that I would find a better design!
I consult you on this Community.airtable to learn the art, the technique of good design.
Thank you very much for bringing us your teaching since Script-Block exists.
It’s very kind of you!
(As I tried to express non-technical nuances in English, I hope I used the right words.)
oLπ
Jun 27, 2020 10:56 PM
Hello, @Bill.French,
I come back to the subject again, not to appear to be the smartest, but because my approach is experimental.
var thisCode = "(async() => {" + ctxScript + "; return(stepOutcome);})(aRecords)";
and
var outcome = await eval(thisCode);
where
thisCode could be (for exemple from STEP1):
await eval("(async() => {let scriptQuestion = “Are you happy?”; let stepOutcome = await input.buttonsAsync(scriptQuestion, [‘Yes’, ‘No’, ‘Back’]);; return(stepOutcome);})(aRecords)");
are focused in what follows:
Assuming that there might be a hidden bias in my experience, in the current state of the results I get:
(1) It seems well that aRecords in
})(aRecords)
at the end of EVAL is never modified anyway by this EVAL code line ;
(2) It seems well that })(anythingElse) is running and giving back the same script results if I first add
let anythingElse
at begin of the script
AND it appears in this case that console.log(anythingElse) is giving back undefined at each script STEP ;
(3) If I’m replacing
})(aRecords)
by })() script is running and giving back the same script results ;
(4) If I’m replacing end-of-script-line
`})(aRecords)
by })`
in
var thisCode = "(async() => {" + ctxScript + "; return(stepOutcome);})(aRecords)";
that becomes then:
var thisCode = "(async() => {" + ctxScript + "; return(stepOutcome);})";
script raised to error then stopped this way:
ERROR
R: Cannot deserialize 15
at main on line
(5) It seemed well that only script line
// update the array with the outcome
aRecords[i]["outcome"] = outcome;
is updating aRecords step by step as you wished.
Be sure that my approach is purely well-intended: I’m not trying to have the last word, nor to look like I’m the smartest.
I’m just trying to understand how this EVAL really works in relation to (aRecords) end-of-script-line, aRecords which I also inspected everything (in my opinion) that’s readable from throughout the script to follow its evolution before coming back here.
Best,
olπ
Jun 28, 2020 08:15 AM
I’m just trying to understand how this EVAL really works
No one truly understands how eval() really works. :winking_face: Perhaps this will help.
This is the magic of eval(); it makes it possible to construct code in a very late binding process purely as a string and then execute that code AFTER the string has been fully constructed.
Jun 28, 2020 08:58 AM
This doesn’t pertain to the ongoing conversation, but is a question regarding the OP, @Bill.French…
Could I use this strategy to save the text of a minified JavaScript library (say Moment.js) in a table, to be implemented in any Script block in that base simply by using eval()
on the value of the field holding the minified library? Could I use that pattern to basically “import
“ libraries I enjoy using into my Scripts?
Jun 28, 2020 09:05 AM
implemented in any Script block in that base simply by using
eval()
on the value of the field holding the minified library? Could I use that pattern to basically “import
“ libraries I enjoy using into my Scripts?
I believe this is possible. Never checked into it, but I have often wondered if this approach wasn’t a pathway to extending the flight ceiling of Script Blocks by dynamically introducing code into a solution for which the code occupies no space (i.e., script memory per-se) in the lately-bound process. Note - you may have experienced a script block is unable to load more than about 2,000 lines of script and minifying seems to help.
My example makes it obvious that …
Jun 28, 2020 09:11 AM
I’ll give it a shot then, when I’m not rolling the internet on my phone :winking_face:
Jun 28, 2020 10:35 AM
I believe this is possible. Never checked into it, but I have often wondered if this approach wasn’t a pathway to extending the flight ceiling of Script Blocks by dynamically introducing code into a solution for which the code occupies no space
It totally works!
Pasting the entire minified moment.js
library into a script block is rejected for making the script too long. However, a long text field can hold the entire minified library:
And that library can be called into the Script block with eval()
, as if you were importing it with import
.
As you see from my screenshot above, you will clearly not have intellisense while editing, and any calls to the eval
'd library will be flagged as errors, but once the library is eval
'd its models can be used in the script.
Thank you for discovering this strategy, @Bill.French – this is going to make the Script block so much more flexible for junior scripters who prefer to lean on other people’s work :winking_face:
Jun 28, 2020 10:50 AM
You’re welcome!
this is going to make the Script block so much more flexible for junior scripters who prefer to lean on other people’s work
Yep - perfect use case for this feature looking for a problem to solve. :winking_face:
you will clearly not have intellisense while editing, and any calls to the
eval
'd library will be flagged as errors
This will probably not be a big issue as libraries – for the most part – are well-tested and few will have the desire to modify them. But, this doesn’t stop any of us from using this approach for creating and managing our own reusable libraries in this way.
Sidebar - if Airtable is able to create a JSON editor for long text fields, it can certainly create and install a code editor for javascript because - wait for it - json is javascript. :winking_face:
Sidebar.2 - BTW, this happened when I envisioned a way to manage code as if it were data and what better example for doing so with the advantageous relationship that Script Blocks share with data tables?
Sidebar.3 - feel free to write the Show & Tell with a title that’s more aligned with what you are showing here; “BlockChaining” doesn’t really express what you’re accomplishing with libraries.
Sidebar.4 - no developer (me included) should ever be given credit for using eval() in creative or potentially dangerous ways. LOL
Jun 28, 2020 02:35 PM
No one truly understands how eval() really works. :winking_face: Perhaps this will help.
Many thanks @Bill.French !
It seems already to me to be the right link but I would ingest and process it during free hours !
Could I use this strategy to save the text of a minified JavaScript library (say Moment.js) in a table, to be implemented in any Script block in that base simply by using
eval()
on the value of the field holding the minified library? Could I use that pattern to basically “import
“ libraries I enjoy using into my Scripts?
Bill had already suggested this in this thread or elsewhere and there you tried, and succeeded! Bravo and thank you very much!
It’s time for me to go on vacation (soon) to try to give something to the Community in return, but for the moment, in javascript, I’m learning to play the Who and the Rolling Stones as perfectly as possible : I’m not composing anything original yet. But it will come !
oLπ
Aug 08, 2020 12:43 PM
Using this approach, very large script “libraries” (perhaps not built in Airtable but certainly) managed in Airtable could be deployed to avoid the Script Block size ceiling. It also means that new scripts and script versions could be deployed without users copying and pasting into each their own blocks.
Hi @Bill.French,
Subject to cross-checking with some of you, this ceiling is at 49999 characters including space :slightly_smiling_face:
Best,
olπ
Oct 15, 2020 07:51 PM
Sidebar.3 - feel free to write the Show & Tell with a title that’s more aligned with what you are showing here; “ BlockChaining ” doesn’t really express what you’re accomplishing with libraries.
Did anyone write this show and tell article? I would love to dive deeper into the inclusion of libraries into JS. This entire article is an incredible example of your superhero status Bill!
Oct 16, 2020 07:11 AM
Did anyone write this show and tell article?
Not that I’m aware of one. And unfortunately, that approach won’t work in automation scripts as eval() apparently isn’t supported in that scripting feature as pointed out recently by @kuovonne.
To be clear, I’m not sure its wise for anyone to follow me off the cliff in a Thelma & Louise journey to use tables as script libraries despite the fact that @Jeremy_Oglesby found the concept somewhat compelling in a script block context.
And to ensure there’s no misunderstanding about my original intent - this approach was created to achieve one thing - to provide dynamically changing script logic while the script was running. This objective is a close cousin of the late-binding of libraries.
Setting aside library inclusion, Airtable should make it possible (in all script environments) to manage code in much the way all JavaScript developers do this - by establishing a model for reusable chunks.
This entire article is an incredible example of your superhero status Bill!
I really appreciate the kind comments, but I must warn you - it didn’t end well for Thelma & Louise. There’s a fine line between superheros and super-nut-jobs.
Oct 16, 2020 07:47 AM
Bill just needs to find his Ted to go on his Thelma & Louise adventure :slightly_smiling_face:
We developed an alternative approach we use at Openside/On2Air that allows for reusable snippets/libraries and better overall management of your scripts.
Check out the product here: https://on2air.com/on2air-scripts
Here is a video review of how it works:
Oct 16, 2020 02:33 PM
We developed an alternative approach we use at Openside/On2Air that allows for reusable snippets/libraries and better overall management of your scripts.
Hello Openside,your solution is really well designed, I think, but after paying for my Airtable-Pro-Plan, I had a careful compromise to make between several Third-Part-Solutions that offer different additional tools to Airtable without being able to pay them all for my current low to minimal traffic.
I wish you all the best for your offer of excellent Add-Ons for airtable.
oLπ
Oct 16, 2020 02:57 PM
To be clear, I’m not sure its wise for anyone to follow me off the cliff in a Thelma & Louise journey to use tables as script libraries despite the fact that @Jeremy_Oglesby found the concept somewhat compelling in a script block context.
And to ensure there’s no misunderstanding about my original intent - this approach was created to achieve one thing - to provide dynamically changing script logic while the script was running. This objective is a close cousin of the late-binding of libraries.
Airtable is not only a very important business tool that must be based on reliable, stable, consistent techniques and must meet the selection criteria of market decision-makers, as @Bill.French teaches us in some of its writings.
It’s also a dream tool that I’ve been waiting for a long time when I found it in a corner of the WEB for a “small lab” that started with Z80s and that today enjoys “As A Service”, “Serverless”, “Micro-Applications”, “Micro-Front-Ends” so don’t hesitate to play Thelma & Louise again from time to time: there is a Audience that loves to follow you on these roads too!
oLπ
Jun 02, 2021 08:46 PM
So I am looking at this solution for Airtable automation since it would mean you could store global functions in a separate table and reference them across your automations.
However, inside Automations I am getting the error “ReferenceError: eval is not defined” despite ‘eval’ showing up as a usable function in the tooltip.
Any ideas? Any workarounds here?
Jun 03, 2021 06:00 AM
There are a few small differences between running a script from scripting app with a button and running a script as an automation. The inability to use eval
in an automation is one of them. Some other differences include using setTimeout
and how fetch
works.
Jun 07, 2021 03:13 PM
Hmm is there a workaround? It’d be great to put global functions into a table that can be referenced directly as code.
Jun 09, 2021 07:52 AM
A CDN + JSON.parse()? But building anything on this sort of functionality seems… unwise.