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