Why do i get an empty cell in my table if the condition is false?

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