ListWidget: table output and line wrap after n items?

Hello community,

I need your thoughts here, please:
Items are read in from a plain text tiddler, line by line.

item1
item2
item3
item4
...
item14
item15

Each item is used as a label for a checkbox-widget and I’d like to force a new table row after 5 items.
Here is a simplified code without the checkbox-widgets. Unfortunately, the </tr>-tag is interpreted as plain text instead of a HTML tag.

<table><tr>
<$list filter="[{data:Customers}splitregexp[\n]]" counter="count">
<% if [<count>remainder[5]match[0]] %>
<td><<currentTiddler>></td></tr>
<% else %>
<td><<currentTiddler>></td>
<% endif %>
</$list>
</tr></table>

Output:

I’m sure that there is a simple solution for this, but I don’t see the wood for the trees :thinking:

Try to treat widgets (including the conditional syntax which is essentially a $list widget) as if they were html tags, adhering to the same hierarchy and nesting rules. In your example you do something like

<table>
  <tr>
    <$list>
      <$list (if)>
        <td>...</td>
        </tr>
...    

The closing </tr> is deep inside the list widgets, not on the same level as the opening <tr>, so it is not interpreted properly.

I see two possible solutions.

One. Build the table row by row. Outer $list widget counts items by groups-of-five, then $list widget in a row lists individual items in this row:

<table>
  <$list filter="count items, divided by five" variable="n starting at 1">
    <tr>
      <$list filter="items (5n - 4) through (5n)">
        <td>...</td>

Two. Use one $list that lists all the items. Arrange them in a desired number of columns by using flexbox instead of a table. I don’t have much experience with flexboxes so I can’t help you further.
This feels like a more flexible (pun intended) way to go than the table approach.

3 Likes

Thank you @vilc, your draft of solution 1 pointed me into the right direction.

I suspected that my opening and closing of tags was unbalanced, but I couldn’t find another solution at this time.
At first it gave me a little headache to find a “counting loop” for my problem, but I found the key in the range operator at last to build a proper filter.

Maybe solution 2 is the better and even more elegant solution, but unfortunately I’m also not familiar with flexboxes. So I ended up building a classic table layout and filled up the empty cells.

<$let rowcount="5">
  <table>
	<$let items={{{ [{dataItems}splitregexp[\n]count[]] }}}  lines={{{ [<items>divide<rowcount>trunc[]add[1]] }}} full={{{ [<lines>multiply<rowcount>] }}} >
      <tr><th colspan=<<rowcount>>>Items: I:<<items>>/F:<<full>>/L:<<lines>></th></tr> 
      <$list filter="[range[1],<items>,<rowcount>]" counter="count">
		<$let cStart=<<currentTiddler>> cEnd={{{ [<cStart>add<rowcount>subtract[1]] }}}> 
		  <tr>
	        <$list filter="[{dataItems}splitregexp[\n]]" counter="index">
		      <% if [<index>compare:integer:gteq<cStart>then<index>compare:integer:lteq<cEnd>] %>
		        <td><<currentTiddler>></td>
		      <% endif %>
		    </$list>
		    <% if [<items>!match<full>then<count>match<lines>] %>
		      <$let start={{{ [<items>add[1]] }}} >
		        <$list filter="[range<start>,<full>]" counter="cnt">
		          <td></td>
		        </$list>
		      </$let>
		    <% endif %>
		  </tr>
	    </$let>
	  </$list>
	</$let>
  </table>
<$let>

Data tiddler:

item1
item2
item3
item4
item5
item6
item7
item8
item9
item10
item11
item12
item13
item14
item15
item16
item17

Output:

grafik

1 Like

One suggestion. ceil[] is more appropriate than trunc[]add[1]. It’s not a big deal, but if your number of entries is a multiple of five, with trunc, you will end up with an extra table row full of empty cells.

1 Like

Thank you scott, good point and you are right.
Currently it is working by accident, because the count for a full pattern and therefore for total lines, too, are being miscalculated.
Therefore the trigger doesn’t create an empty row because it is one number too high.

I will give it a try to debug it and use the ceil operator instead.

Enhanced the code with a range widget to show the problem.
In the header the letters are
I for items,
F for full pattern and
L for total lines.

Items in row: {{!!rcnt}} <$range field="rcnt" min="1" max="10" default="1" increment="1" default="5"/>

<$let rowcount={{{ [{!!rcnt}match[]then[5]else{!!rcnt}] }}} >
  <table>
	<$let items={{{ [{dataItems2}splitregexp[\n]count[]] }}}  lines={{{ [<items>divide<rowcount>trunc[]add[1]] }}} full={{{ [<lines>multiply<rowcount>] }}} >
      <tr><th colspan=<<rowcount>>>Items: I:<<items>>/F:<<full>>/L:<<lines>></th></tr> 
      <$list filter="[range[1],<items>,<rowcount>]" counter="count">
		<$let cStart=<<currentTiddler>> cEnd={{{ [<cStart>add<rowcount>subtract[1]] }}}> 
		  <tr>
	        <$list filter="[{dataItems2}splitregexp[\n]]" counter="index">
		      <% if [<index>compare:integer:gteq<cStart>then<index>compare:integer:lteq<cEnd>] %>
		        <td><<currentTiddler>></td>
		      <% endif %>
		    </$list>
		    <% if [<items>!match<full>then<count>match<lines>] %>
		      <$let start={{{ [<items>add[1]] }}} >
		        <$list filter="[range<start>,<full>]" counter="cnt">
		          <td></td>
		        </$list>
		      </$let>
		    <% endif %>
		  </tr>
	    </$let>
	  </$list>
	</$let>
  </table>
<$let>