Rendering Children() using template based on some attribute

I’m looking for advice on the approach to take when I have a common parent page showing different types of children. For example, I’m creating blog pages for displaying lists of books or movies or changelog entries, etc. The parent page is identical, but movies should render as a table with Title, Year, Date Watched, and Rating. Books should render as Title, Author, Year, Date Read. Changelog entries should just be a list, etc.

Is there a common approach to this? Currently I am putting a conditional in the template, like so:

^if($Prototype(child[0])=="pMovie")^
	<table><tr><th>Title (Year)</th><th>Watched</th><th>Rating</th></tr>
	^children(/Templates/HTML list page/movie item)</table>
^else^
	^children(/Templates/HTML list page/displayexpression only)
^endif^

Basically, it’s just asking “Hey, what type of notes do we have here?” and swapping out the template accordingly. When it’s only 2 cases (like above) this seems fine, but I’m afraid it begins to smell once that becomes 3 or more variations.

Would it make sense to name the templates to match the prototype name and do something like this (untested)?:

^children(/Templates/HTML list page/$Prototype)</table>

But that leaves me with no good way to render the table header (in this example).

I feel like this must come up often but I’m unsure of the best route.

Why not let each child inherit its template from its prototype? So, an instance of Movie would use MovieTemplate, and an instance of List would use ListTemplate.

The pMovie prototype already has a template assigned for rendering the full-page, “detail” view of a movie (“HTML Movie”).

You can’t do that as you’re passing a literal path that doesn’t exist, ‘$Prototype’ being treated as a literal string.

What about this. First add a user string attribute TemplateString. Now the relevant part of the template above is:

^action(
$TemplateString="/Templates/HTML list page/" + $Prototype.substr(1);
)^^children(^value($TemplateString)^)^^action($TemplateString=;)^

So for a note of prototype ‘pMovie’ the template used is the template at path /Templates/HTML list page/Movie. I’m not sure )late here so no time to run tests, but this alternate shorter form might work:

^children(^value("/Templates/HTML list page/"+$Prototype.substr(1)^)^

I think you’re onto something. I’ll give this a try shortly. Thank you.

Also, consider agent that don’t export as pages, but can be ^included, using specified templates.

This ended up working for the rows:

^children(^value("/Templates/HTML list page/"+$Prototype(child[0]).substr(1)+" item")^)^

@mwra your shortened example works. It just needed the child[0] part to get the correct prototype.

Now I have to find a way to handle the wrapper for the ^children call (table headings, etc.). Perhaps a function but that’s really just moving the same set of conditionals out of the template into a function. Feels cleaner though.

It’s possible I’m overthinking this. I have a history of stumbling with exports, so this seems like a good opportunity to try sorting it out in my head :slight_smile:

Over-thinking? Not necessarily, but unless this is a one-off disposable task it does warrant some reflection and improvement. But, here, we only have part of the tale. Missing:

  • Are we exporting an agent (container) and alias children, or a container note and its children?
  • Are all the child notes/aliases expected to be exportable as files/pages in their own right?
  • Are all children the same type (i.e. same prototype)? It is sort of implied they are, but not unambiguously stated.

The last is most relevant as it affects how the child data is used. For instance if different children of the same container use different per-row data, the overall table headings may not be pertinent (or fit) the per-row content is relevance and number of columns, etc.

You method of taking the prototype-derived type from the first child would make sense if all children are of the same type. However, for the enclosing table you first need to step back and ask if the column headings and number of columns are consistent for all data types in play. Otherwise you would need to offer a means to generate separate per table enclosing table HTML code.

The first step to unpicking this is to clarify (as possible design constraints):

  • are all child notes, in the context of any single export use of the code, all of the same ‘type’ (prototype or whatever).
  • does the enclosing HTML table code and header row vary per type? If so:
    • do what degree does the table change?

That will help save you wasting time on improvements that hit a dead end. I write that with experience of backing out of ‘improvement’ dead-ends because I forgot to properly define the context and inherent design constraints.

There are a lot of different ways to resolve the above. The best choice depends a lot, IME, on recognising the context. If the latter is onerous work, then you’re probably optimised enough.

HTH :slight_smile:

Thanks Mark. Your assumptions are correct: It’s an agent with alias children all of the same type that need to also be exported as separate files. Your initial suggested approach works well until the table header needs to be different based on the type of children. I’m going to punt on that for now and make the columns close enough to work with the same table header for the types of children I’m dealing with.

I appreciate you helping me think this through!

Happy to help - been there!

A parting thought, consider a config note with a dictionary holding the subject’s data-type (or simply the per-type prototype’s name) and the template name. Note that if you use unique template name’s the need to quote the entire path disappears—good with deeply nested templates and long template names.

A separate dictionary (same keys, different attribute) could hold a path to a boilerplate for the table opening and header row. Of course, in the container the table wraps the child include so you’'d need to remember to add the table close (but that should be generic.

Or, to polish further you might return the boilerplate HTML table opening via a function allowing you to add some custom information.

How far you go down the rapid hole is personal choice; the last few are as much for other readers as for yourself. The last few ideas are overkill for something only to be used and thrown away. If the code will have regular use (or infrequent repeated use) then a clearly abstraction of the process (don’t forget to document it!) makes sense.

1 Like