Help

Re: Help with a loop script

Solved
Jump to Solution
3104 0
cancel
Showing results for 
Search instead for 
Did you mean: 
Elizabeth_Green
4 - Data Explorer
4 - Data Explorer

I am very new to Airtable, and am after help with the script block. What I would like to achieve is exactly what has been given as an example here.

This is what I have written:

let lineItemsTable = base.getTable(‘Order Line Items’);
let siteOrdersTable = base.getTable(‘Label Orders’);
let productsTable = base.getTable(‘Product Inventory’);

let siteRecord = await input.recordAsync(‘Select a Site’, siteOrdersTable);
if (siteRecord) {
let labelRecord = await input.recordAsync(‘Select a Label’, productsTable);
if (labelRecord) {
let quantity = parseInt(await input.textAsync(‘Quantity’), 10);
let recordId = await lineItemsTable.createRecordAsync({
‘Job’: [{ id: siteRecord.id }],
‘Item’: [{ id: labelRecord.id }],
‘Qty’: quantity
});
let allRecords = await lineItemsTable.selectRecordsAsync();
let record = allRecords.records.find(record => record.id === recordId);
output.markdown(Added new Label Item: **${record.getCellValueAsString('Description')}**);
let addAnother = await input.buttonsAsync(‘Add another Label’, [‘Add Another’, ‘Done’]);
if (addAnother === ‘Add Another’) {
let labelRecord = await input.recordAsync(‘Select a Label’, productsTable);
if (labelRecord) {
let quantity = parseInt(await input.textAsync(‘Quantity’), 10);
let recordId = await lineItemsTable.createRecordAsync({
‘Job’: [{ id: siteRecord.id }],
‘Item’: [{ id: labelRecord.id }],
‘Qty’: quantity
});
let allRecords = await lineItemsTable.selectRecordsAsync();
let record = allRecords.records.find(record => record.id === recordId);
output.markdown(Added new Label Item: **${record.getCellValueAsString('Description')}**);
}
} else {
output.markdown(‘Done’);
}
} else {
output.markdown(‘No Label Picked’);
}
} else {
output.markdown(‘No Order Picked’);
}

Im not sure where or how to place the “For” loop… Any help would be greatly appreciated.

1 Solution

Accepted Solutions
kuovonne
18 - Pluto
18 - Pluto

Welcome to the Airtable community!

You don’t say why you want a loop, but I’m guessing that you want to continue creating line items until the user clicks the “Done” button.

There are many ways of doing things in code. Although you could use a for loop, for loops are usually for situations where you need to keep track of which iteration of the loop you are in. In this case, I would use a do ... while loop. A do ... while loop is for when you want to execute the code at least once, and then repeat it until an exit condition occurs.

let addAnother;
do {
  // insert code for picking a label/product, a quantity, and creating the record
  addAnother = await input.buttonsAsync('Add another Label', ['Add Another', 'Done'])
} while (addAnother == "Add Another")

There are also a few things that could be done with your script to make it run more efficiently and be easier to maintain. However, I don’t want to overwhelm you, especially if you are only re-creating the script as a way of teaching yourself JavaScript.

See Solution in Thread

4 Replies 4
kuovonne
18 - Pluto
18 - Pluto

Welcome to the Airtable community!

You don’t say why you want a loop, but I’m guessing that you want to continue creating line items until the user clicks the “Done” button.

There are many ways of doing things in code. Although you could use a for loop, for loops are usually for situations where you need to keep track of which iteration of the loop you are in. In this case, I would use a do ... while loop. A do ... while loop is for when you want to execute the code at least once, and then repeat it until an exit condition occurs.

let addAnother;
do {
  // insert code for picking a label/product, a quantity, and creating the record
  addAnother = await input.buttonsAsync('Add another Label', ['Add Another', 'Done'])
} while (addAnother == "Add Another")

There are also a few things that could be done with your script to make it run more efficiently and be easier to maintain. However, I don’t want to overwhelm you, especially if you are only re-creating the script as a way of teaching yourself JavaScript.

I did not see this pattern coming. :winking_face: Pure elegance.

Thanks for you help - it has worked exactly as I wanted.

There are also a few things that could be done with your script to make it run more efficiently and be easier to maintain. However, I don’t want to overwhelm you, especially if you are only re-creating the script as a way of teaching yourself JavaScript.

Thanks for the advice - I am open to changes to improve…

After your do ... while suggestion, this is the new code:

let lineItemsTable = base.getTable('Order Line Items');
let siteOrdersTable = base.getTable('Label Orders');
let productsTable = base.getTable('Product Inventory');

let siteRecord = await input.recordAsync('Select a Site', siteOrdersTable);
if (siteRecord) {
    let addAnother;
    do {
        let labelRecord = await input.recordAsync('Select a Label', productsTable);
        if (labelRecord) {
            let quantity = parseInt(await input.textAsync('Quantity'), 10);
            let comments = await input.textAsync('Comments/Notes/Customisation');
            let recordId = await lineItemsTable.createRecordAsync({ 
                'Job': [{ id: siteRecord.id }],
                'Item': [{ id: labelRecord.id }],
                'Qty': quantity,
                'Comments': comments
                });
            let allRecords = await lineItemsTable.selectRecordsAsync();
            let record = allRecords.records.find(record => record.id === recordId);
            output.markdown(`Added new Label Item: **${record.getCellValueAsString('Description')}**`);
            addAnother = await input.buttonsAsync('Add another Label', ['Add Another', 'Done']);
        } else {
            output.markdown('No Label Picked');
        } 
    } while (addAnother == "Add Another")
} else {
    output.markdown('No Order Picked');
}

I have come across another issue, your advice would be welcomed. I have added in the following into my script:

let comments = await input.textAsync('Comments/Notes/Customisation');
let recordId = await lineItemsTable.createRecordAsync({ 
     'Job': [{ id: siteRecord.id }],
     'Item': [{ id: labelRecord.id }],
     'Qty': quantity,
     'Comments': comments
     });

The script won’t let me continue without inputting text into the comments area - Id like to make this optional - how can this be done?

Thanks, your help is much appreciated :slightly_smiling_face:

Here are some thoughts. Please remember that all of these comments are just suggestions and if you are pleased with the operation of your script, sometimes just getting a working script is enough.

  • You do a great job of providing feedback to the user when the user doesn’t doesn’t pick a record. Consider adding feedback at the end of the script indicating that it is done.

  • I recommend adding comments to your script explaining how the script works. If you ever need to come back to the script, it can be hard to remember exactly what was going on.

  • Consider storing your table and field names in variables at the top of your script. That way if your table and field names change in your base, it is easier to update your script. Even better would be to use the new Script Settings beta.

  • If the user does not pick a site record at first, the script will do not create any records and will not ask for another. This isn’t a big deal because the user can just run the script again.

  • If the user enters something unexpected when you ask for a quantity, your script might produce unexpected results. For example, if the user types 1,000, your script will think that is 1. Depending on how well your users are at following instructions, this may or may not be a problem. You probably don’t need the 10 when you call parseInt, as it is highly unlikely that users will be entering a number in a different base.

  • I recommend learning how to write your own functions and breaking down your code into different functions. With functions you can put “guard clauses” at the beginning of the function with an early return to avoid the really long if statements.

  • Currently the user has to wait for the creation of each new junction record. For the purposes of the demo script, that made sense. However, you might want to consider asking for all of the line items up front, and then creating them in one batch after the loop. It isn’t a big deal for scripting block, but if you ever want to write scripting actions for automations (which have limits on processing time), batch operations are faster.

  • You are getting the newly created record by calling selectRecordsAsync() and then using a find. You could get the new record more directly by using allRecords.getRecord(recordId). However, does the user really need to know the exact description? Consider providing conformation by repeating back some of the input values so you don’t have to call selectRecordsAsync.

  • By now, @Bill.French is probably rolling his eyes at me for overwhelming you when I said that I didn’t want to in my previous post.

Currently Scripting block will not continue until actual text is included in the input.textAsync() box. I tend to use one of two workarounds:

  • I use a button before the text input to see if there is text input,
  • Or I tell the user in the prompt to enter a single space if there is no input, then I trim the string to remove the white space.