Construct table while iterating using the $list widget

Hi,

I’m trying to understand if it’s possible to generate a wiki-style table using the $list widget. My naive attempt looks like this:

|!col1|
<$list filter="1 2 3" variable="item">
|<<item>>|
</$list>

That doesn’t work however. What’s the right way to generate a table that way? I could resort to a full-out HTML table, but hoping it wouldn’t be necessary.

it work well with html

<style>
table,tr,td{border:1px solid silver;}
</style>


<table>
<tr> !col1 </tr>
<$list filter="1 2 3" variable="item">
<tr><<item>></tr>
</$list>
</table>

As lh… wrote you should use proper HTML table syntax.

Using the STYLE element is only for easy debugging with copy & paste here. For a production code you should use a TW stylesheet.

So headings can use the TH element and items should use TD. Thefollowing table contains 2 columns to make the structure a bit clear

<style>
table,tr,td{border:1px solid silver;}
</style>

<table>
  <tbody>
    <tr><th>col1</th><th>col2</th></tr>
    <$list filter="1 2 3" variable="item">
      <tr><td><<item>></td><td>xx</td></tr>
    </$list>
  </tbody>
</table>

1 Like

I wonder if someone who understands the core implementation can explain in layman’s terms why this is so. I discovered the same thing (and rediscovered it several more times when I temporarily forgot it!) But plenty of wikitext is properly expanded inside <$list> ... </$list>. What are the technical reasons this doesn’t work with table rows?

I think the issue is you need a blank line inside the list so it is treated in block mode, but the wikitext tables need no gap gaps or the table breaks.

  • Somewhere along the line I gave up on this and use html tables except for very simple tables. As soon as I use lists within the tables I go strait to html tables
  • Is this a valid approach? I would need to experiment but I did this many times in the past and gave up. Madness is doing the same thing over and over thinking you will get different results.

I stand to be corrected.

The code that implements the wikitext markup for tables expects one contiguous chunk of text defining the entire table. However, when using the list widget, each iteration of the widget is processed separately.

1 Like

Ahh. Thank you. That makes it clear.

Going to HTML seems like a hack to me though I do understand sometimes things are tough to do otherwise. I’m OK with the workaround.

Is it possible to accumulate the wiki markup in a variable and then process it as a whole?

Yes, though with larger tables there might be a performance impact with that approach.

In my case, it’s not going to be, could you paste a bit of that concept?

@Surge I am not sure exactly what you mean when you say;

But in tiddlywiki another way to gather things into a whole is via transclusion,

  • place some tiddlywiki script in a tiddler and transclude it eg {{$:/invoicing/accounts-table}} or to have it apply to the current tiddler {{||$:/invoicing/accounts-table}}
  • and use fields in the current tiddler to drive the table, or wrap the transclusion in a let widget to set variables that apply inside the transcluded tiddler.

@TW_Tones , what I meant was a concept similar to eval in many languages. You pass it a string that conforms to the syntax of that language and the function executes it.

In the context of tiddly wiki, I’m trying to avoid dealing with an HTML table entirely. Instead, I’m trying to see if there’s a way to accumulate a string containing the definition of a table and then have a macro/widget render the resulting string.

The string would start out by containing just |!col1| and then a loop would add a row in each iteration so that at the end the total “wiki” string would be something like:

|!col1|
|content|
|content|

Is there a way to implement the above idea?

I think wikify is close to what I want?

I’m not sure how practical this would be for complicated rows, but here’s an extremely basic example:

\define header() | !Header | !Header |
\define row() | $(currentTiddler)$ | test |

<$let lbr="""
""">
<$list filter="[range[20]] :map[<row>] [<header>] +[putfirst[]] +[join<lbr>]">

<<currentTiddler>>
</$list>
</$let>

That’s a necessary line break before <<currentTiddler>>, by the way: without it, the parser will revert to inline mode and the wikitext table will collapse.

Getting a little more complicated:

\define header() |!Tiddler |!Created |
\define row() |$(currentTiddler)$ |<$text text={{{ [[$(currentTiddler)$]get[created]format:date[MMM DD, YYYY]] }}} /> |

<$let lbr="""
""">
<$list filter="[prefix[Hello]] :map[<row>] [<header>] +[putfirst[]] +[join<lbr>]">

<<currentTiddler>>
</$list>
</$let>
1 Like

Yes, I am sure you can do as you ask, the specifics need to be addressed, the two trick you need to establish is as far as I see;

  • Build a variable, possibly through the append operator, but you need to insert line breaks;
  • Wikify the resulting variable to get the end result

However to me this is a strong case for returning to the “what you want” and choosing the best way to impement it, not choosing a way and trying to make it work. I would reconsider using tiddlywiki table markup because it is somewhat fragile from expierence.

I belive there are features in TW5.3.x that will help do this kind of thing much more easily, but it remains to be fully explored.

\define pipe() |

<$wikify name="tablified" text={{{ [[1]] [[2]] [[3]] +[join<pipe>] +[addprefix<pipe>] +[addsuffix<pipe>] }}} mode="inline" output="text">

<<tablified>>
</$wikify>
1 Like
\define pipe() |
\define tablify($items$)
<$wikify name="tablified" text={{{ $items$ +[join<pipe>] +[addprefix<pipe>] +[addsuffix<pipe>] }}} mode="inline" output="text">

<<tablified>>
</$wikify>
\end

<<tablify "[[1]] [[2]] [[3]]">>

I hope you can see how things get problematic if you want more than one row.

1 Like