Migrate from {#child ..} to {{childTemplate ..}}



  • The docs recommends that the new {{childTemplate ..}} is used instead of the old {#child ..}.

    I need some help understanding how I can migrate.

    Here is what I need to do in order to migrate with minimal rewriting of my child templates:

    • change recipie to html
    • marshal the complete data object (@root)
    • marshal some parameters

    But it seems that I will need to rewrite quite some code anyway.

    Q1: Why is the new way recommended?
    Q2: Will {#child ..} be deprecated?
    Q3: Will {#child ..} perform badly in jsReport 3?

    My child templates are built upon the fact that they always have the complete data tree available. Would it make sense to simply give them all data in order to preserve compatibility? I would probably need a wrapper in order to specify html as recipie (or is html default with new syntax?):

    function prepareData(drawingIndex, options) {   
        return options.fn({
            data: options.data.root,
            drawingIndex
        })
    }
    
    function htmlTemplate(name) {
      return {
        name,
        recipe: "html"
      }
    }
    

    The helpers would be called like this:

    {{#prepareData 0}}
      {{childTemplate (htmlTemplate "myTemplateName")}}
    {{/prepareData}}
    

    This seems like an awful lot of wrapping compared to the old syntax:

      {#child myChildTemplate @template.recipe=html @data.drawingIndex={{0}}}
    


  • marshal the complete data object (@root)

    The parent data are automatically merged into the childTemplate requests.

    Q1: Why is the new way recommended?

    The old syntax is just string replace. You need to string serialize/parse complex parameters in order to send them to the child. You can't wrap it as a normal helper.
    This syntax was implemented some 8 years ago as a workaround because templating engines don't support asynchronous helpers.

    jsreport now supports async helpers so it's finally possible to do it better. The new syntax, using a common helper call can benefit from being part of the templating engine. It gets the current context. It can be wrapped with another helper. Its simply more natural.

    Q2: Will {#child ..} be deprecated?

    There isn't a plan to do it now.

    Will {#child ..} perform badly in jsReport 3?

    It should perform the same. Its same code.

    I would probably need a wrapper in order to specify html as recipie (or is html default with new syntax?):

    It doesn't force HTML.

    This seems like an awful lot of wrapping compared to the old syntax:

    You can wrap childTemplate helper in your own custom helper.

    function myChildTemplate(name, paramA, opts) {
        return childTemplate.call({
            ...this,
            paramA
        }, {
            name,
            recipe: 'html'
        }, opts)
    }
    

    or you can even skip using child templates extension and write your own helper for rendering other templates

    async function myHelper(name) {
      const jsreport = require('jsreport-proxy')
      const response = await jsreport.render({  
           template: { name },
           data: this
      })
      return response.content.toString()
    }
    

    I will try to update the docs to make this more clear...



  • Thanks.
    Could you please confirm or clarify the below regarding child templates and components. I'm really starting to like the new concept, but I need to be sure of the below before taking design decisions.

    I need to know if I have grasped the below correctly and if I missed anything important.

    Child templates called with new syntax {{childTemplate.. }}

    • In the child html I get access to this, i.e. the current data context from parent
      Example usage in child {{this.someItemData}} or simply {{someItemData}}

    • child templates does NOT have access to data from outer scopes in the parent
      Example: {{../this.name}} will not work in the child

    • Helpers in child templates can access the complete report data structure via this
      Example:

    function() {
      console.log(this.someDataFromTheRoot)
    }
    
    • child templates can run scripts (i.e. beforeRender..)

    • Global helpers are accessible from child templates

    • In order to call a template which is not html recipe, I need to inject a recipe change into the childTemplate call.

    • Helpers in child templates gets an options object prepended as last argument in calls. The data.root in the options object is the root of the report dataset.

    Components

    • In the component html I get access to this, i.e. the current data context from parent, i.e. same as child templates

    • Components does NOT have access to data from outer scopes in the parent. Same as child templates.

    • Helpers in components can NOT access the complete report data structure via this
      But if I need data from elsewhere in the report data structure I can prepare a special data package to deliver to the component via a wrapper as in your examples.

    • Child components can NOT run scripts (i.e. beforeRender..)

    • Global helpers are accessible from components

    • Components are forced to html recipe, i.e. no need to inject recipe change as for child templates

    • Helpers in components gets an options object prepended as last argument in calls. The data.root in the options object is the current context from the parent, i.e. NOT the root from the report dataset.

    Edit:
    I just realized that I can use global helpers to get hold of the report data root even from a component which operates in another context. This could make components usable in every case where I used to have child templates. Does this make sense?

    const jsreport = require('jsreport-proxy');
    
    function getUserName() {
      return jsreport.req.data.user.name;
    }
    
    

Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.