Categories > OpenTBS with DOCX >

Loading a subtemplate based on data from MergeBlock()

The forum is closed. Please use Stack Overflow for submitting new questions. Use tags: tinybutstrong , opentbs
By: Sarah
Date: 2012-07-21
Time: 01:30

Loading a subtemplate based on data from MergeBlock()

I want to load a different subtemplate based on a property or my main block.

Say I have two templates: t1.xml and t2.xml

I have a large object that looks basically like:
ItemList
   -Property1
   -Property2
   -Items
      -Item1
         -Property3
         -Details
            -Detail1
            -Detail2
      -Item2
         -Property4
         -Details
            -Detail3
            -Detail4
...etc

I run MergeBlock on ItemList.Items, which gives me a table for each item with details about that item. I have a couple of subblocks that handle printing some properties (like Detail1 or Detail2 listed above) in a template that I include in each table. This is working fine, the issue is that now I want to be able to use different subtemplates in different tables based on a property of the Item (like Property3). I had hardcoded the template name and had it merging onload. Now that I want the filename to come from Property3, I need to change this to load after the MergeBlock runs, but hopefully before the subblocks run, because otherwise the subtemplate will not be populated with the Details. Is this possible? Is there some secret trigger between MergeBlock and the merging of each subblock?

I think the answer is no, but I am really hoping it is yes. I will continue to love OpenTBS either way - it has made this project possible.

Any suggestions are welcome. I hope I explained clearly enough.

Thank you,
Sarah
By: Sarah
Date: 2012-07-23
Time: 19:23

Re: Loading a subtemplate based on data from MergeBlock()

I have been trying to do this with the onformat and subtpl arguments. I added a function:

function f_load_sub_template($blockName, &$CurrRec, &$CurrPrm, &$TBS){
    $TBS->LoadTemplate('templates/'.$CurrRec->template.'.xml');
    $TBS->MergeBlock('Drawing',$CurrRec);
    $TBS->Show();
}

Where my HTML in my main template is:
[Items;block=w:body;sub3=desc]
[Items;onformat=f_load_sub_template;subtpl]

And in my sub-template:
[Drawing;block=w:pict;sub1=details]
[Drawing_sub1.Detail1;block=v:group]

I don't know that I am using this correctly, as I am receiving the following error:
TinyButStrong Error when merging block [Array]: Data source Id 'Items' is unsupported because function 'tbsdb_Items_open' is not found.

The sub-template loads fine and I can print the value of $CurrRec and it seems to have the data I need, but the sub-template is not populated with the data sent in the MergeBlock() call.

It seems like using a true sub-template like this could maybe do what I need... Will it make a difference to use the script method instead of the onformat method? Or am I passing $CurrRec incorrectly? Can a sub-template interact with the main template's blocks like this?

Thank you for any help!

Sarah
By: Skrol29
Date: 2012-07-23
Time: 23:06

Re: Loading a subtemplate based on data from MergeBlock()

Hi Sarah,

> Is there some secret trigger between MergeBlock and the merging of each subblock?

If you are using automatic-sublocks, the it is interesting to know that they are merged after all fields or the current record are merged.
Thus, if one one the field do insert a sub-template in the current section, then the sub-template becomes available for the sub-merging.

Here is an example with HTML (I know you are using DOCX, but it may be clearer with an HTML example) :

Main template (main.html) :
<table border="1" cellspacing="0" cellpadding="4">
  <tr>
    <td bgcolor="#0099CC"><strong>Name</strong></td>
    <td bgcolor="#0099CC">Details</td>
  </tr>
  <tr>
    <td>[ItemLst.name;block=tr;sub1=Details]</td>
    <td>[ItemLst.Property;file=[val]]</td>
  </tr>
</table>

Sub-template 1 (tpl_1.html):
sub-template 1
<div style="color:red">
[ItemLst_sub1.id;block=div]
</div>

Sub-template 2 (tpl_2.html):
sub-template 2
<div style="color:blue">
[ItemLst_sub1.id;block=div]
</div>

PHP code:
<?php

include_once('tbs_class.php');

$ItemLst = array();

$ItemLst[] = array(
  'name' => 'Item1',
  'Property' => 'tpl_1.html',
  'Details' => array(
    array('id'=>'Detail1'),
    array('id'=>'Detail2'),
    array('id'=>'Detail3'),
  ),
);

$ItemLst[] = array(
  'name' => 'Item2',
  'Property' => 'tpl_2.html',
  'Details' => array(
    array('id'=>'Detail4'),
    array('id'=>'Detail5'),
    array('id'=>'Detail6'),
  ),
);

$TBS = new clsTinyButStrong;

$TBS->LoadTemplate("main.htm");

$TBS->MergeBlock("ItemLst", $ItemLst);

$TBS->Show();

If you are using manual sub-template then it should work the same.

But in fact, instead of sub-template, I think you should try with conditional merging.
You could have one section instead of sub-template 1, and another section instead of sub-template 2.
By: Skrol29
Date: 2012-07-23
Time: 23:20

Re: Loading a subtemplate based on data from MergeBlock()

> Will it make a difference to use the script method instead of the onformat method?

Parameter "onformat" just helps you to change the current value using your PHP code.
You can use it for loading a sub-template, but your have to save the result in $CurrVal.

Parameter "script" doesn't need a current value, and is for executing another PHP script, but it does quite the same.

> Or am I passing $CurrRec incorrectly?

I don't think so. The syntax you are using if for parameter "ondata";
Parameter "onformat" has $CurrVal instead of $CurrRec.

> Can a sub-template interact with the main template's blocks like this?

I'm surprised your code can work. And I'm afraid that duplicating the "w:body" XML entity may produce an invalid DOCX document.
By: Sarah
Date: 2012-07-23
Time: 23:32

Re: Loading a subtemplate based on data from MergeBlock()

Wow! I must have tried every combination of things AROUND this answer and just never landed quite on target. Thank you so much - I was totally out of simple ideas and headed into some seriously complicated and inefficient directions! I am using automatic subblocks - I didn't realize I could use [val] on its own in the file field that way.

Now that I have a working version (Thank you!) I am intrigued by the thought of conditional merging for this problem. To explain my project a little further, each page of my docx contains a table (for layout reasons, not because it should be a table - think HTML in the 90's) with info from the top level array (Items). There is a large cell in the middle which contains an image and dimensions of the image (v:shapes and text boxes created by the 'Details'). The dimensions are dynamically created to go with the image in most cases. I was using a single included file for this. However, recently I added a couple of new images that do not need dynamic dimensions - only static ones. This is why I created several new templates to hold the static dimensions. Would the conditional merging mean conditionally choosing the template within the docx file? Or including the body of each of my templates in the docx and conditionally choosing which one is populated and kept?

I see I am too slow to respond since you have replied again since I began typing.

Thank you for explaining onformat and script - I tried them all (including ondata) but it is all a haze now unfortunately.

I am surprised and glad every time it works :D I originally had it set to duplicate w:table on each block, but I found the document it produced ended up being all one big table so one had to split the table to type between, which did not work for my purposes. When I switched to w:body (the only tag at a higher level than w:table, it worked perfectly. When I open the document.xml of a produced file the w:body tag is not duplicated. I thought that perhaps the MergeBlock did not duplicate the tag that contains it, only the tags under it? That is the behavior I have seen, in any case. My docx produces no errors.

Just another of those things about TBS and OpenTBS that just sort of works and I don't fully understand why - I'm just grateful. Thank you again for your excellent responsiveness and expertise.