thisRow = View.Last() does not respect sort order

I’m working on a dynamic character sheet for a tabletop game and have the following table:

image

It has a list of afflictions and the number of stacks of each affliction affecting the character (i.e. the number of times the character is affected).

I also have a section that represents a “quick summary” of important info, and so I have a view table showing only the non-zero afflictions. They are ordered by stacks, not by name, since that’s the more important information in the quick view:

image

Thus, the view has both a sort condition and a filter condition:

image
image

At the end of the turn, the smallest stack is decreased by one. So I want to find out what the last row of the table view is. To illustrate the problem, I created a new button column with a condition:

image

But this does not work, as you can see:

image

Note that Temperance is not the last row in the Active Afflictions table, nor in the Afflictions table. Based on poking around, it appears that the Active Afflictions.Last() call ends up referring to the last row after the filter, but before the sort. It should refer to the true last row instead.

3 Likes

Hi @Alexis_Hunt,

Thank you for posting a detailed walk-through here. This is something that’s been difficult to do in Coda and shouldn’t be, so I appreciate the setup that highlights how this causes more work than necessary.

For this instance, I’d say the best workaround is to create a named formula in the canvas and use your filter there. Then for the button, disable it for anything that is not the result of that named formula.

Thomas pinged me about your support ticket, so I took a peak at your doc and believe you had a canvas formula like this already:

[Active Afflictions].Filter(Stacks = [Active Afflictions].Stacks.Min()).Sort(true, Afflictions.Affliction).First()

If you name that formula “Target Affliction”, then you can use that in your button disable field with:

thisRow!=[Target Affliction]

This should do what you need, but you’re definitely correct that it shouldn’t take this much work to get there.

2 Likes

Hi @Alexis_Hunt, welcome to the community.

The thing with sorting is that it’s only applied on output level but not the dataset level. When you’re referencing a table in a formula, the data set you’re receiving is always the one before sorting.

My preferred way to go about this would be:

  1. Add a column in your table for “Order” that would calculate like:
thisTable.Sort(false, Affliction).Sort(false, Stacks).Find(thisRow)
  1. Sort your view on that new Order column instead of explicitly specifying Stacks descending and Affliction descending (note that in the formula above the order of columns to sort on is reverse)
  2. In your disable if formula, have something like
thisRow.Order != thisTable.Order.Max()
1 Like

@BenLee Ah, excellent catch, thank you! That is a nice and straightforward solution. I hope that this can get improved in the future!

@Paul_Danyliuk My point in making this post is that the behaviour shouldn’t be this way—there’s just no intuition for the fact that the filter, but not the sort, is applied at the dataset level. From a programming language design point of view, it doesn’t make sense, because it means that the actual object [Active Afflictions] refers to something that you never actually see. If it referred to the full unfiltered dataset, even that would be preferable! It’s not just that it requires workarounds, but also that it’s extremely difficult for a user like myself to understand why the formula isn’t working—there is no documentation of this behaviour or anything.

2 Likes