I am making a template helper that will insert inline SVG icons into my templates. I want to pass an argument to add an additional CSS class (which will be used to change the default size, color, etc.).
What I Expect
<button>
<svg viewBox="0 0 78 73" class="svg-icon svgWhite" version="1.1" ...>
<polygon id="icon-star" points="39 ... 60">
</polygon>
</svg>
</button>
What I Get
<button>
"[object Object]"
<svg viewBox="0 0 78 73" class="svg-icon" version="1.1" ...>
<polygon id="icon-star" points="39 ... 60">
</polygon>
<!--[object Object]-->
</svg>
</button>
My Template
<template name="whatever">
<button>{{{icon.star svgWhite}}}</button>
</template>
My Template Helper
Template.registerHelper('icon', {
star: function (userClass, userWrapper) {
var wrapper = (userWrapper == undefined) ? "i" : userWrapper;
var addlClass = (userClass == undefined) ? "" : ", " + userClass;
var svgWidth = 78;
var svgHeight = 73;
var svgCode = '<polygon id="icon-star" points="39 .... 60"></polygon>';
var icon = '<'+wrapper+'>' +
'<svg viewBox="0 0 ' + svgWidth + ' ' + svgHeight + '" ' +
'class="svg-icon' + addlClass + '" ' +
svgConfig + '>' + svgCode + '</' + wrapper + '>';
return icon
}
});
Reference: https://github.com/meteor/meteor/tree/devel/packages/spacebars#helper-arguments
Your template helper registration looks broken, I think you are trying to achieve a simple thing using an overcomplicated way.
When you start using triple brackets syntax and writing HTML in your javascript, you know you are probably doing it wrong : you should probably use template inclusion to perform what you need.
First, we define the parent template, it will include a child template that we can configure using attributes (these attributes will act as the data context of the child template).
<template name="svgButton">
<button type="button">
{{> svgIcon class="svg-white"}}
</button>
</template>
Then we define the child template, we can use attributes passed from the parent template.
<template name="svgIcon">
<svg viewBox="0 0 {{width}} {{height}}" class="svg-icon {{class}}">
{{! warning, polygon is a self closing tag like img}}
<polygon id="icon-star" points="..." />
</svg>
</template>
We can define helpers that will either take the value of the data context if present, or a default value :
Template.svgIcon.helpers({
width:function(){
return this.width || 78;
},
height:function(){
return this.height || 73;
}
});
So we may include the child template using this form for advanced customization :
{{> svgIcon class="svg-whatever" width="16" height="16"}}
EDIT :
What happens when I have 20+ icon templates. Do I then have 20+ template helpers with repeatable functions (not DRY)?
This is the approach I would use :
First, define all your icon svg content as different templates.
<template name="svgIconStarContent">
<polygon id="icon-star" points="..."/>
</template>
{{! repeat 20 times...
but this is DRY compliant because each time this is a different icon}}
Then we can use UI.dynamic
to include the correct template based on a parameter name.
https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/
<template name="svgIcon">
<svg viewBox="0 0 {{width}} {{height}}" class="svg-icon {{class}}">
{{> UI.dynamic template=svgIconContent}}
</svg>
</template>
Finally, in the parent template, we can pass the name of the template we want to insert dynamically so the content of the icon may vary when invoked with different values.
{{> svgIcon svgIconContent="svgIconStarContent"}}