the below conditions are inside a table:
..#if data.carrierInfo.tableInfo.len() > 4 {
(
table.cell(x: 6, colspan: 1, rowspan: 5, align: center + horizon)[
*SEE SUPPLEMENT TO THE BILL OF LADING*
],
[]
)
},
..#if data.carrierInfo.tableInfo.len() <= 4 {
data.carrierInfo.tableInfo.map(row => row.pairs().filter(pair => pair.at(0) != "bolPreview").map(pair => pair.at(1))).flatten().map(value => [#value])
},
i first had the first condition as follows:
..#if data.carrierInfo.tableInfo.len() > 4 {
table.cell(x: 6, colspan: 1, rowspan: 5, align: center + horizon)[
*SEE SUPPLEMENT TO THE BILL OF LADING*
],
},
when it was like above, i would get an empty first cell in my table, even though the condition was false.
when i changed the first condition to be like below, i didn’t get the empty first cell anymore:
..#if data.carrierInfo.tableInfo.len() > 4 {
(
table.cell(x: 6, colspan: 1, rowspan: 5, align: center + horizon)[
*SEE SUPPLEMENT TO THE BILL OF LADING*
],
[]
)
},
why do you think the way it was didn’t work and why it works when i return a sequence?
Your example doesn’t compile for me:
Error: cannot spread content
╭─[/main.typ:9:3]
│
9 │ ..if true { table.cell[Hello!] }
───╯
Which leads me to suspect that you were typing if condition { cell }
without the spread operator before if
(the two dots ..
).
Note that:
if condition { body }
, without an else
, is a shorthand for if condition { body } else { none }
. This means that, when the condition failed, it’d insert none
into the table, which is equivalent to an empty cell.
..args
, where args
is an array (positional) or dictionary (named arguments), is the only way to pass a variable amount of arguments to a function. That is, if you want to pass 0 or 1 arguments depending on a condition (your case), or any amount of arguments unknown until the code is run, you must use an array like you are doing.
- This is because the spread operator
..
simply passes all values in the array as arguments. If the array is empty, nothing is passed:func(..(1, 2, 3)) == func(1, 2, 3)
func(..()) == func(..none) = func()
- Remember that your
..if condition { body }
is a shorthand for ..if condition { body } else { none }
, so when your condition is successful, it will expand the array returned by body
into table cell arguments, but when the condition fails, it will be ..none
which is itself a shorthand for ..()
, i.e. don’t pass any additional arguments. That’s why your new version works.
- So, the old version did not work as it did not use the spread operator, and would instead attempt to add a
none
cell.
If you want to read more about this, this documentation page talks about it: Arguments Type – Typst Documentation
you’re right in what you suspected, sorry about that!
and thanks a lot, i’ve got so much to learn about Typst!
1 Like
If ..
is a spread operator, then you can’t use raw #
in code mode, it just won’t compile.
The example indeed does not compile, for the above reason, and because the column number is not known. Default in 1 and x: 6
is invalid for it. You also don’t show how data
is defined. It just so happen that I recognize this data structure from How do i make a cell's colspan depend on the column title (in my data)?. Otherwise, we can only pretend that it’s #let data = (carrierInfo: (tableInfo: range(5)))
, which will still fail for the last complex function chaining.
For the chaining, you can make it more readable by destructuring the pair:
data
.carrierInfo
.tableInfo
.map(row => row
.pairs()
.filter(((key, _)) => key != "bolPreview")
.map(((_, value)) => value))
.flatten()
.map(value => [#value])
Or even shorter:
data
.carrierInfo
.tableInfo
.map(row => row
.pairs()
.filter(((key, _)) => key != "bolPreview")
.map(((_, value)) => [#value]))
.flatten()
1 Like