We saw in this post that buttons can be used to execute a script against a specific record.

In this post I’ll show a way to run scripts with a base-wide scope.

What do we mean by “base-wide scope”? Ordinarily a script button will execute an action against a single record. But sometimes we want to execute a script that runs against the whole base (or at least against a set of multiple records, perhaps those that meet a certain condition). How do we implement a button with this wider-ranging scope?

Of course, we could use a button script exactly as shown in the previous post - there’s nothing to say that the script has to use the record we have selected when clicking the button. But, from a user’s point of view, this might be confusing, so a more logical implementation might be to add a “Global actions” table to your base where global scripts can be configured and executed.

Let’s start by adding this script to your base:


let table = base.getTable('Global actions');
let record = await input.recordAsync('Pick a record', table);
if (record) {
    console.log(record.name)
}

Then set up your “Global actions” table like this (see previous post for the basic script button set up):

We need to modify our script so that clicking on the different buttons causes a different script action to be taken. We’ll use functions to make this happen.

Functions are self-contained blocks of code that perform specific tasks or calculations and can be “called” at different points during the execution of your script.

A function is written like this:


function myFunction() {
    // do something here
}

Sometimes you might want to pass “arguments” or input parameters to the function, but in our case, this isn’t necessary.

We can now modify the boilerplate script button code to run a different function depending upon which button the user clicks on.


let table = base.getTable('Global actions');
let record = await input.recordAsync('Pick a record', table);

if (record) {
    if (record.name == 'Archive records') {
        archiveRecords();    
    } else if (record.name == 'Update statuses') {
        updateStatuses();
    } else if (record.name == 'Send emails') {
        sendEmails();
    }
}


function archiveRecords() {
    console.log('Archiving records')
}

function updateStatuses() {
    console.log('Update statuses')
}

function sendEmails() {
    console.log('Send emails')
}

The 3 functions are defined at the bottom of the code block and the if statement uses the input.record to decide which function to run. This code:


if (record.name == 'Archive records') {
    archiveRecords();    
}

is saying: “If the record name equals ‘Archive records’ then run the function archiveRecords()

This approach gives us a flexible framework to set up and run a number of global action scripts. It also has the benefit of putting the global action buttons in their own table which might a better user experience for base users.

The downside of this appoach is that this is all in a single script and it could get long and complicated if you have a large number of complex actions that need to be set up, but for most applications it should be workable.

Update (8th Sept 2020)

I was using this methond in a recent project and found that, in practice, the solution outlined above was not complete, at least not in an Airtable context.

With Airtable scripts we will often run select, update, create or delete methods using the await keyword so that the scripts waits until the function has returned before proceeding. However, you can only use await within an async function, so we need to adjust the script to accomodate this:


if (record) {
    if (record.name == 'Archive records') {
        await archiveRecords();    
    }
}

const archiveRecords = async() => {
  // Airtable script code here
}