Add rows using a canvas button
Pressing a button to link data from two tables
You’ve probably run into situations where you needed to create a new table with only a portion of the data from a larger table. This blog post explains how to accomplish this using a powerful pattern.
In my previous blog post about modifying rows using a canvas button, I highlighted the importance of the ForEach
function. Here's a relevant excerpt:
Within the
ForEach()
function, each item from the list is renamed asCurrentValue
. This might seem a bit perplexing initially, but once you grasp thatForEach()
meticulously processes each item and executes a specific action on it, the purpose becomes clear. It's a concise way of expressing exactly that functionality.
I also detailed where the results were stored.
The filter generates a list of objects (items), which are then used as a starting point. Each item is associated with a specific column and we define the value to be placed in the corresponding cell of that row.
We’re developing a function to create email lists based on subsets of a main list. This involves two tables: the main table and a new table that will store the filtered results. Our example filters by region, a key consideration in Belgium due to its linguistic diversity. The northern region primarily speaks Flemish, while French is the dominant language in Wallonia. Creating separate lists for each region simplifies exporting.
Using a filtered table view
I’ve noticed that clients often use filtered views of a table as the basis for their work. For example, they might filter the table to show only people living in Flemish cities.
Here’s an example: This view of the “DB Cities” table is filtered to show only results for “Flanders” and currently displays 128 rows.
Creating a second table from this filtered view is simple, as shown here when starting to write a formula. The canvas formula provides all the objects in this filtered view (the items below in blue represent the objects and their values displayed in the column).
The button’s appearance is as follows:
Everything works as expected.
What could go wrong?
If you use dedicated tables for this type of work with clear names and untouched filters, then there’s not much that can go wrong.
However, humans enjoy playing (we are homo ludens according to the Dutch historian Huizinga), and this can lead to applying different filters without considering that this might affect the result of the canvas button associated with the table view. This unintended consequence of playfulness is, as you can imagine, not productive.
A filtered view is a shortcut for what you see below: the full functionality including a filter on the base view. This is likely a safer way to proceed since everything is together, and you don’t have to look in two places (the right panel for the filtered view and the canvas button).
Follow these patterns:
The pattern I propose is straightforward:
- Avoid using table views in your canvas buttons, as they can cause unclear errors, particularly for new Coda users.
- Another option is to manage filters within the canvas button. However, this requires manual changes for any modifications and assumes a level of Coda expertise that may not always be available.
- The third and recommended option is to use controllers, which I will explain below. This approach is beneficial regardless of your Coda proficiency.
Controllers
Here’s a look at some controllers. I’ve combined two types here to illustrate a principle. We’ll eventually use only one type. The region controller is a multi select, while the city is a relation based on DB Cities.
I’ve configured the options to allow selection of cities only within Flanders (as shown below).
For those unfamiliar with the chaining logic used here, let me explain. This controller has access to currentValue
because it's a relation, not a select list. currentValue
represents each selectable city, linked to a region in the referenced table. Therefore, we can filter for cities within the selected region. The multi-select controller (the first one) handles region selection. If no regions are selected, we retrieve all regions. Since this list can be extensive (hundreds of regions), we extract only the unique ones.
While this setup functions, it's not the most efficient approach, although I've encountered similar implementations in client documentation. I've demonstrated that it works, but it's not optimal.
Selecting single or multiple items offers a quick and easy way to get started, especially useful for prototyping. However, to establish relationships between your data, it’s necessary to convert these selected items into tables. This allows you to leverage relational database principles. I’ve done this, and we now have two controllers with relations available.
We’ll now convert the region selection into a relation. This is a quick two-step process, as shown below, resulting in the table named “DB Region.
The first controller needs to be rebuilt as a relation, not a select list. I’ve removed the old one and created a new one, as shown below.
I’ve rewritten the filter using options, as shown below. This new approach is more streamlined. We now reference the region via the controller. If no region is selected, we retrieve all entries from the “DB Region” table.
The final piece is integrating these controllers into the button that adds rows to the target table. The code snippet below handles this. The currentValue
in the first part replaces the thisRow
you'd use when working inside the table. Because we're using a canvas button and working externally, we need currentValue
.
High floor, low ceiling
Last week, I discussed the importance of simplifying Coda for new users, given its extensive capabilities. This controller-based approach exemplifies that philosophy. Controllers streamline the process, eliminating the need for users to interact directly with table views or button formulas. Users simply configure the controllers to their preferences, and the task is completed quickly and easily. This does require the maker to carefully plan the setup beforehand.
One final point: I used the forEach
logic from my previous post here again to demonstrate the pattern. While not strictly necessary in this modifyRows()
scenario (since source and target tables are identical, providing a list of objects), it doesn't hurt. Adopting this pattern is a good practice that can save time and trouble. Sometimes, understanding the formal logic isn't essential; simply using the pattern is sufficient.
Hopefully, this post has shed some light on this common Coda challenge and empowered you to create more interactive and insightful data experiences. On a personal note, creating these in-depth posts takes a lot of time and effort. While I love sharing my knowledge, a little support goes a long way. If you found this helpful, what about a donation or sharing this post with your fellow Coda enthusiasts? Every bit of encouragement helps!
My name is Christiaan, and I regularly blog about Coda. While this article is free, my professional services (including consultations) are not, but I’m always happy to chat and explore potential solutions. You can find my free contributions in the Coda Community and on X. The Coda Community is a fantastic resource for free insights, especially when you share a sample doc.
About Huizinga
Johan Huizinga, a Dutch historian, introduced the concept of “Homo Ludens,” which translates to “playing man,” in his 1938 book, Homo Ludens: A Study of the Play-Element in Culture. In this work, Huizinga explores the vital role of play in shaping human culture and society. He argues that play is not merely a frivolous activity but an essential aspect of human nature with profound implications for our understanding of civilization. The Latin word ludens is the present active participle of the verb ludere, which itself is cognate with the noun ludus. Ludus has no direct equivalent in English, as it simultaneously refers to sport, play, school, and practice.