Action Button Info

Hey all!

Anyone have additional info on using the custom widget template “Action Button”? I haven’t been able to find much info on how to use it, and don’t fully understand the syntax of the formula(s) used.

I’m hoping to be able to be able to use it to duplicate a record X number of times, so I’d be especially thankful for any tips on setting the button to do multiple actions/a single action multiple times!

Thanks in advance :slight_smile:

Apologies, it is indeed utterly undocumented. It exists as a workaround; hopefully we’ll have a better solution before long. The Action Button needs access to a column, with a formula that returns a value of this form:

{
    "description": "Some description text",
    "button": "Text of the button itself",
    "actions": [ACTIONS_TO_APPLY],
}

The actions field is a list of actions, having this form (for the most common kinds):

[
  ["AddRecord", "TableId", None, {"Col1": Value1, "Col2": Value2, ...}],
  ["UpdateRecord", "TableId", rowId, {"Col1": Value1, "Col2": Value2, ...}],
  ["RemoveRecord", "TableId", rowId],
]

The "actions" field should be a list of actions, and each action itself has the form of a list. So a single AddRecord action would look like [['AddRecord', 'MyTable', None, {"ColA": "ValueA"}]] (with two pairs of brackets).

There is an example of an Action Button to duplicate rows here: https://public.getgrist.com/ubYNJ1PPN9Vn/Action-Button/m/fork; it was used for a recent webinar.

2 Likes

Awesome, thanks!

Is there a way to make this work with reference columns? When I use the action button to duplicate a record, the new records have errors in reference columns (I just used “ReferenceColumn”: $ReferenceColumn in the action code)

Ah yes, $ReferenceColumn attempts to give you a useful object (e.g. to enable $Ref.Field notation), but for these actions you need the underlying numeric identifier. Try replacing $ReferenceColumn with either

int($ReferenceColumn)

or

$ReferenceColumn.id

Either one should fix it.

1 Like

How to you refer to a field in a different table in the dictionary of column values?

Also, what are the possible actions? I actually want the user to see the prompt for a reference list so she/he can pick the desired item–although ideally she would select a row in the source table to populate the row in the target table.

So many easy things are so hard when the plumbing just isn’t there for action. Grist is too much a spreadsheet with neither enough viewing flexibility, sensible navigation and actions beyond typing in cells.

1 Like

I can’t get this to work. I sort of got it once, but the value in a target reference column had the right text but was not linked back to the source table.

Now, nothing works for the action button.

Here is the error:

"ActionButton" cells should contain an object with keys "button", "description", "actions". Missing keys: "button", "description", "actions"

Here is the formula from the action button:

{"description" : "Schedule a task", "button" : "Schedule", "actions" : [["AddRecord", "Details", None, {"Item": Routine_Maintenance.lookupOne(id=$id).cat}]]}

Looks like the dictionary has all 3 keys: description, button, actions. (Yes, there is an equal sign before the dictionary literal, but that won’t copy/paste.)

I’ve edited the formula multiple times to hopefully get it right. Clearly, I didn’t. I delete the widget to add it all over again because you only seem to parse the formula in the ActionButton column once when it is added. I got it work (incorrectly) once. Now it just never works at all.

I know you appreciate it when users show their undying gratitude for the great work you do, but sometimes the frustration is a bit much.

  1. Python formulas are essentially arbitrary code even when wrapped in a dictionary literal. There has to be a way to introduce cosmetic line breaks and to make the edit box larger. Even Excel allows both.
  2. Need a lot better documentation of the objects and functions that Grist exposes to Python.
  3. Widgets are fundamentally designed to be big rectangular areas that can hold a table, a card, a series of cards or a plot frame. How does a single little floating button get a huge rectangle for which the context is unclear? The button might apply to the document as a whole, but it might also apply to a row, in which case it should be the rendered value inside a column – not unlike a choice item.

Sorry, but 3 hours later for something like this has me wondering if you should release features in such raw state just to get marketing credit for having the feature. Don’t you want the feature to be usable before you release it?

So many things in the design of this product are very well thought out from the beginning (like granular permissions). As you scramble to keep up in the feature battle don’t succumb to “featuritis” just adding things by cramming them in. Better to delay and get it right than get it wrong–that’s worse than no feature at all. Hard discipline when competition in this category is truly frantic.

Well, I got the button to appear and perform an action.

It always selects row 1 of the referred to table instead of the last row selected.

So, it always fills in the same text and it doesn’t not return a reference link, which is what I must have.

@Lewis_Levin, your source data table must be selected in the “SELECT BY” custom widget option, and then the custom widget will use the selected row

1 Like

What is the use of “Add Record” and “UpDate Record” as an action button?

As far as I understand, any change you do to a record is already saved by Grist.

While this is interesting and fast, sometimes you WANT the record to be saved ONLY after clicking a save button. Not sure that can be done with Grist. (and it would also be interesting that the save button would only appear if all required fields are filled.

What you are suggesting is a form that works more like a typical web form, and less like a spreadsheet. Grist doesn’t support it now, though it’s easy to imagine that such an interface (with an explicit “Save” button) would often be preferred for data entry over the current Card view. It would be a nice feature (but @Lewis_Levin’s warning against “featuritis” is a valid one!)

I would not recommend the “Action Button” for this. It’s so hard to use that it’s hard to ever recommend, but it exists as a workaround for some situations where Grist doesn’t give any solution (e.g. adding a set of 100 records prefilled according to some rules).

For forms with a Save button, it could be implemented as a Custom Widget. That requires writing html/css/javascript, and/or making use of an existing form builder. That’s easier to imagine as a very usable thing that anyone could use.

1 Like

Thanks Dmitry.

“some situations where Grist doesn’t give any solution (e.g. adding a set of 100 records prefilled according to some rules).”

Any pointing to some article, video or forum topic showing how to do something similar to that (adding 100 records prefilled according to some rules)?

I couldn’t find a public example, so created one here: Student Grades - Grist.

The idea is that you want to record exam grades for students. Select the first exam in the top-left table, and you’ll see the grades for it. If you select another exam, you’ll see that there isn’t a record for each student’s grade yet. You can type in as many new records as you have students (selecting a different student reference for each, and entering the corresponding grade). But the ActionButton widget allows you to create those records with one click, so that you only need to enter the grade for each.

For reference, the formula to create that ActionButton logic is:

actions = []
existing_grades_students = set(Exam_Grades.lookupRecords(Exam=$id).Student)
for s in Students.all:
  if s not in existing_grades_students:
    actions.append(["AddRecord", "Exam_Grades", None, {
      "Exam": $id,
      "Student": s.id,
      "Grade": None
    }])
return {
  "button": "Add {} records".format(len(actions)),
  "description": 'Add "{}" records for {} students'.format($Exam, len(actions)),
  "actions": actions,
}
3 Likes

That last example was great! And perfect timing for something I had just begun working on

An additional question:

Is it possible to create an action button that would trigger action buttons for other (i.e. linked) records?

1 Like

Hi,

I am using this solution for something else. For example we need a system in our school to count (and later bill) the copies for every student. And I managed to change the code for our needs, and it is working well. With the sumary tables, and everything. For example, I added a colum to the Exams Table, calling it Copies, and instead of None (for the former Grades) it uses the value entered in that record. Works like a charm!

We can input copies for individual students manually (in the former all Grades table) when they come for copies, or for all studenst in the former Gradebook table, but I would like to add the option to add studens from a specific class, instead of All students. The way the code works now is, it adds a record for all studens in the Student table, but I would like to filter that by class. So when a teacher gives the secretary an original an asks for 1 copy per student for his class, she just needs to select the class, enter the number of copies, and click the action button, and voila, it adds the amount to every student in that class.

Is it possible to do? I’m almost sure it is, but I can’t figure out how.

Answering my own question:

Yes, it is possible to do, but not the way I imagined. I had to add a column with the class to the first table (Materias) and then it just worked.

But I have a new challenge: I want to be able to add a student to more than just one group. And that i could not figure out yet. For example, instead of just beeing part of the 7A group, a student could also be part of the boys from sevent grade, or all the seventh graders, or sport group, etc.

How can we accomplish it?

If your Clase column is a text one, I’d create a Clases table, and convert the Clase column to a reference list pointing to Clases.

By the way, as this topic is marked as solved, posting here would tend to reduce the visibility of your questions. You should create a new topic when you have a new question, it will be more visible.

Ok, thank you.

my clase is a table, and I tried with reference list. Everyhting from the normal usage in Grist works with that, but the Action Button does not. Probably just a matter of code I don´t know.

When I posted the first question, I did not see the solved part. Maybe an admin could move this to a new post. But I saw that you, @jperon are a smart guy and solves a lot of problems here. Maybe we can solve this and then it can remain here for those who seek examples on ActionButton.

I’ll post a screenshot with the reference list and the code here

Well, I did figure it out looking at the code one more time. the solution was to change the part wich reads:

for s in Estudiantes.lookupRecords(Clase=$Clase.Clase):

to this:

for s in Estudiantes.lookupRecords(Clase=CONTAINS($Clase)):

Now everything is the way it should be.

1 Like