Actions triggered by a primary button on table views

🎯 Tip: How to Create a Primary Action Button in Table, Deck, or Other Views in AppSheet

As of now, AppSheet does not natively support primary action buttons in table or deck views. I've already submitted a feature request, but until it arrives, we’ll have to get a bit creative… okay, a bit hacky too 😅.

This tip can be adapted to any use case, but the example we’ll use is: generating a PDF containing data from child records, selectively triggered from a button in the parent table. The trick lies in creating an intermediate form that acts as the launcher of an automated process.


🧩 General Structure of the Algorithm

  1. From the parent table, the user taps a primary action button.

  2. This button opens a form based on a minimalist slice of the same parent table.

  3. The form includes an EnumList field (base type Ref), where the user selects the parent records whose child records will be processed.

  4. When the form is saved, a temporary helper row is created.

  5. A Bot detects this row and launches a chain of actions.

  6. Actions are executed on the selected child records.

  7. Finally, the helper row is deleted.


⚙ Step by Step

🧱 DATABASE STRUCTURE

1. Add two new columns to the Parent Table

  • [action_confirm]

Show More
  • Type: Yes/No
  • Reset on edit: ON
  • Initial value: IF(CONTEXT("View") = "slice_form", true, false)
  • [parents]

Show More
  • Type: EnumList base type Ref to the parent table
  • Required: Yes
  • Suggested values / Valid if: Table[ID] -- or any subset you prefer
  • Initial value: Table[ID] -- or any subset you prefer

2. Create a Slice from the Parent Table

Show More

This slice will be the source for the form view. It must allow adding records, and include at least these columns:

  • [RowNumber]

  • [ID]

  • [parents]


3. Create a Form View Based on This Slice

Make sure only the [parents] field is visible (unless you want to show others).
Position: Ref

Event Actions - Auto assign: Go Back


4. Create the Action to Launch the Form

Show More
  • Type: Go to another view within this app

  • Formula: LINKTOVIEW("items_slice_form")

  • Position: Primary

This action will appear as a primary button in table or deck views.


🤖 Automation with Bots

5. Create a New Bot on the Parent Table

Show More
  • Event: App data change (Adds or updates)

  • Condition: [action_confirm] = true

Bot Processes on the Parent Table

6. Add a Process to the Bot: Action on a Set of Child Rows

Show More
  • Table: Parent

  • Action type: Execute an action on a set of rows

  • Target table: Child

  • Rows to execute on: FILTER( "Children_Table", IN([parent_id], [_THISROW].[parents]) )

  • Action to execute: Could be generate PDF, update rows, send emails, WhatsApp, etc.

Final Action in the Bot: Delete the Auxiliar Row

Show More
  • Type: Delete

  • Table: Parent

  • Condition: Leave it blank if this comes after your main process — the record will simply be cleaned up.

💡 Important

This auxiliar row is not intended for end-users — it’s a purely internal trigger mechanism.
You can hide it from views or display it in a debug/admin view if needed.


Conclusion

With this method, we can simulate a primary action button that kicks off complex processes like document generation, multi-record updates, batch communications, and more — all without SELECT() and without unstable hacks. Just pure AppSheet logic.

This pattern also sets you up for even more advanced use cases like: sending batch emails or WhatsApp messages, generating grouped reports, flagging records for review, and much more.

The important thing is that you understand that the primary button takes us to a slice-based auxiliary form, and then, when you save, it creates a row in the base, triggers a series of actions, and then deletes the row.

I hope this helps, and I apologize for any previous misunderstandings.

4 4 510
4 REPLIES 4

This seems like an interesting idea but sadly the steps lack too much detail to follow. By step 2, there are already questions. For example for the line that reads:

  • Initial Value: TRUE using CONTEXT("View") = "NewViewBasedOnSlice"

I guess the reference to True is not needed and the Initial Value should simply be the Context statement? The "NewViewBasedOnSlice" should refer to the name of the form we are about to create in the next step? Perhaps?

It just got worse after that. @Gustavo_Eduardo it would be good if you could come back and edit this or provide a sample app to show what you intended. Thanks

Dear AppSheet community members, I sincerely apologize for uploading this tip without having fully reviewed it (perhaps I did review it, but at the time of uploading, I was very busy and must have pasted something that wasn't checked). In any case, I want to especially thank the user @alphacp because (although I received 4 likes, and those likes made me think things were going well), he is the only one who took the time to read it and saw that it didn't actually work.

Well, thank you very much @alphacp . I have corrected it now. Please let me know if it works for you, and if not, I will gladly help you solve the problem. Greetings from Argentina.

Thank you. I think I am making progress but still a little confused by the recommended actions in step 3:

  • Add a label field, but set it as non-editable to avoid system validation issues.
  • Configure the view to replace any other when the form opens.

The LinkToForm() that is called in Step 4, will open the form but will assume create a new record but in Step 1 you said to only allow updates on the slice. So this errors and perhaps this is where your tip regarding a label field comes in to play but I tried everything I could think of to get around this so maybe the last bullet is important but I could not get my head around that either, sorry. 

I think I perhaps need I need to add a Row key, or perhaps there is a second table at play here?

Ok @alphacp  I've modified it. Please take a look and let me know if you have any questions. Best regards, and again, thanks for letting me know.

Top Labels in this Space