Was trying to figure this out and the blog posts I came across via Google didn’t help. Here’s what I want to do.
I have a Tab list control like this:
This is what its Items
property looks like:
1 2 3 4 5 6 |
[ "Page 1", "Page 2", "Page 3", "Page 4" ] |
And I have an arrow button on the page.
All I want is that clicking the arrow should take me to the next page (i.e. select the next item in the list). Easy?
Here’s what I did.
First I created a global variable (could have been a context variable too I suppose) and set it to the first page.
1 |
Set(gblSelectedTabPage, "Page 1"); |
On the Tab list, I set the DefaultSelectedItems
to that variable.
1 2 3 |
Table( { Value: gblSelectedTabPage } ) |
This is just capturing the default state of the Tab list basically. By default it starts at Page 1 anyways, now I make it explicit by linking it to a variable. The beauty of this is that now I can change the variable to change the selected tab.
I set the OnSelect to be this:
1 |
Set(gblSelectedTabPage, Self.Selected.Value) |
Which is to say when I select/ click on a Tab list item, change the variable to be the value of that selected item. And this in turn causes the DefaultSelectedItems
to change to that, thus changing the selection.
So far so good.
And then I changed the OnSelect
of the button to be this:
1 |
Set(gblSelectedTabPage, "Page " & (Index( Split(gblSelectedTabPage, " "), 2 ).Value + 1)) |
This is a mouthful so here’s what it does:
- First, it uses the
Split
function to split the contents ofgblSelectedTabPage
along a space. So, ofgblSelectedTabPage
is currently Page 1, what we get is “Page” and “1”. - From this it uses the
Index
function to get the 2nd element. Which is “1” in the above example. - It increments this. So “1” becomes “2”.
- And concatenates with “Page ” to make it “Page 2”.
- And this is set as the new value of
gblSelectedTabPage
, which causes that tab to be selected!
There is, of course, one issue with this. If I keep pressing the button it will keep going. So we need to do something about that.
First, I make a small change to the Tab list. Rather than specifying the items in line, I make a variable and use that.
1 2 3 4 5 6 7 8 9 |
ClearCollect( gblTabListItems, [ "Page 1", "Page 2", "Page 3", "Page 4" ] ); |
So the Items
property of the Tab list is now gblTabListItems
.
I do this coz now I have an easy way of knowing the number of elements in the list. CountRows(gblTabListItems)
gets me that.
And then I modify the OnSelect
of the button to be this horrendous thing:
1 2 3 4 5 6 7 8 9 |
With({ currentPageNumber: Index( Split(gblSelectedTabPage, " "), 2 ).Value }, With({ nextPageNumber: If(Value(currentPageNumber) < CountRows(gblTabListItems), currentPageNumber + 1, 1) }, Set(gblSelectedTabPage, "Page " & nextPageNumber) ) ) |
I shouldn’t really call this horrendous, it’s not too bad. But in fairness to me I am still working my way around thinking of code in this functions sort of way. ☺️
The reason it looks a bit complicated is coz I am trying to do a bit more than before, but also keep the code readable. Essentially, what I want to do compared to the earlier code where I was just incrementing the page number is that I now want to check if the page number is lesser than the total number of pages and only then increment; and if not, just set it to 1 so we start again.
For this I make use of the With
function.
This evaluates a formula for a single record. So the outermost formula above is basically:
1 2 3 4 5 |
With({ currentPageNumber: Index( Split(gblSelectedTabPage, " "), 2 ).Value }, // do something... ) |
What it does is, it creates a temporary variable called currentPageNumber
and that contains the current page number which I extract using the same formula I was doing earlier. The difference is, this variable is only visible within this formula when it runs. Use and throw. Which is good coz now I can use this variable in the rest of the code within the With
function to keep things readable.
Think of the With
function as With(variable definition section, action section)
.
Sadly, you can’t refer to a variable that is created within the With
function within the variable definition section. You can refer to it in the action section only. But I want a second variable that has the new page number, so what I do is that in the action section I use yet another With
function. Like this:
1 2 3 4 5 6 7 8 9 |
With({ currentPageNumber: Index( Split(gblSelectedTabPage, " "), 2 ).Value }, With({ nextPageNumber: If(Value(currentPageNumber) < CountRows(gblTabListItems), currentPageNumber + 1, 1) }, // do something ) ) |
So now the second With
function has a nextPageNumber
variable that is the currentPageNumber
+ 1 if it is less than the total number of pages (CountRows(gblTabListItems)
) or 1 if it exceeds.
Readable, right?
So now the action section of the second With
function can act upon it – i.e. Set(gblSelectedTabPage, "Page " & nextPageNumber)
.
Put everything together, and we get:
1 2 3 4 5 6 7 8 9 |
With({ currentPageNumber: Index( Split(gblSelectedTabPage, " "), 2 ).Value }, With({ nextPageNumber: If(Value(currentPageNumber) < CountRows(gblTabListItems), currentPageNumber + 1, 1) }, Set(gblSelectedTabPage, "Page " & nextPageNumber) ) ) |
Now if I keep clicking right, after the last page I return to the first.
Nice!🕺