ZPT-JS tutorial - Macros

METAL

Macro tag attributes are called Macro Expansion Tag Attribute Language (METAL) statements. METAL statements behave exactly as in ZPT. The main difference, which is really a difference in Path expressions, is the means of finding another template which contains macros. There is no Zope tree in which to locate templates. Use-macro tag uses expressions (ZPT's version does not, it uses literals).

Local macros

Local macros are defined at the same HTML file where they are invoked. An example of definition of a local macro:

<ul data-define-macro="list">
    <li data-repeat="item items">
        <span data-content="item">An item</span>
    </li>
</ul>
                

That macro generates an unordered list iterating through the items variable. Let's invoke them; to do this, the next HTML code must be at the same file.

<div data-define="items [10 20 30]" data-use-macro="'list'">
    Macro goes here
</div>
                

ZPT-JS allows to uses expressions when using macros. The next HTML code invokes the same macro if the value of listMacro variable is list:

<div data-define="items [10 20 30]" data-use-macro="'listMacro'">
    Macro goes here
</div>
                

External macros

External macros are defined at a different page that where they are invoked. They only differ how they are invoked; if we want to invoke the macro list defined in macros.html file:

<div data-define="items [10 20 30]" data-use-macro="'list@macros.html'">
    Macro goes here
</div>
                

External macro files must be preloaded before the template is rendered, so code is async:

zpt.run({
    command: 'preload',
    root: document.body,
    dictionary: dictionary,
    callback: function(){
        zpt.run();
        [ your code here ]
    }
});
                

Because external macro files must be preloaded before the template is rendered, ZPT-JS must to know the list of external files invoked in the template. If we use literal string expressions or expressions that can be evaluated using only dictionary there is nothing to do. But if we use an expression that can not be resolved at first like this:

<div data-use-macro="anObject/templateName">
    Macro goes here
</div>
                

If anObject/templateName evaluates to aMacro@macros.html and there is no rederence to macros.html in other macro invokations, that macro invokation will throw an exception: Macros in URL 'macros.html' not preloaded!. To resolve this issue we must set manually the list of external macro files we want to use when executing the ZPT call:

zpt.run({
    command: 'preload',
    root: document.body,
    dictionary: dictionary,
    declaredRemotePageUrls: [ 'macros.html', 'moreMacros.html' ],
    callback: function(){
        zpt.run();
        [ your code here ]
    }
});
                

URLs are by default relative to current URL. You can also use absolute URLs:

zpt.run({
    command: 'preload',
    root: document.body,
    dictionary: dictionary,
    declaredRemotePageUrls: [ '/path/to/your/macro/macros.html' ],
    callback: function(){
        zpt.run();
        [ your code here ]
    }
});
                

And in your HTML code:

<div data-use-macro="'myMacro@/path/to/your/macro/macros.html'">
    Macro goes here
</div>
                

Context object provides a conf property to set a prefix to all relative URLs:

context.getConf().externalMacroPrefixURL = '/path/to/your/templates/';
        

Then if you use an URL like macros.html it will be replaced by /path/to/your/templates/macros.html.

Optionally you can add a fail callback function to manage initialization errors:

zpt.run({
    command: 'preload',
    root: document.body,
    dictionary: dictionary,
    callback: function(){
        zptParser.run();
        [ your code here ]
    },
    failCallback: function( msg ){
        [ your code to manage initialization errors here ]
    }
});
                

msg is the error message.