How to use an array of objects on a foundation email template? - handlebars.js

Im using foundation emails, i can use variables on a template by wrapping them in a raw tag, for example:
<raw><%= myVariable %></raw>
Now, I need to add attachments, and attachmeants come as an array with this form:
attachmentsData: [
{
id: '301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-01.png',
title: 'Screenshotfrom2018-11-1916-43-01.png',
url: 'https://s3.eu-central-1.amazonaws.com/dev-messaging-attachments/301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-01.png',
},
{
id: '301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-02.png',
title: 'Screenshotfrom2018-11-1916-43-02.png',
url: 'https://s3.eu-central-1.amazonaws.com/dev-messaging-attachments/301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-02.png',
},
],
On the documentation it also says that i can loop over arrays that are declared in src/data in yml format.
However in my case i need the array of objects to come from the backend.
but if it comes from the backend it i have to parse it with the raw tags.
But if use the raw tags i cant use the each helper:
https://foundation.zurb.com/emails/docs/panini.html#custom-data
Do you know how to loop over this array?
note that, If i do <raw><%= myArray[0].name %></raw> this works and prints the right value.
Any tips? Thanks

If <raw><%= myArray[0].name %></raw> works, then the following should work too.
<% myArray.forEach(data => { %>
<raw><%= data.name %></raw>
<% }); %>

Related

tinyMCE4 can't get external templates to work

I'm very new to tinyMCE (and to JavaScript), so I'm sorry if the answer to my question is obvious. (I'm also working on code and files that another developer created and that I'm not overly familiar with.)
I need to use an external template file for tinyMCE4, and I can't get it to work. I've looked at the tinyMCE4 documentation, but I don't understand where I'm going wrong.
The tinyMCE init is in an index.cfm file, and the list of templates is in a separate file, template_list.js.
Contents of template_list.js:
var tinyMCETemplateList = [
["Name", "templates/file1.cfm", "Name."],
["Name2", "templates/file2.cfm", "Name2."],
...
];
In index.cfm, I've included "template" in the plugins line.
To pull in the templates to appear as a list in a drop-down so the user can choose a template, I've tried:
template_external_list_url: "tinymce/js/tinymce/template_list.js"
With this, when I run the program and click the Insert Template button I get a "No templates defined" error.
I've also tried:
templates : [{url:"tinymce/js/tinymce/template_list.js"}]
With this, the Insert Template dialog box appears, but the drop-down is empty, and the raw code from template_list.js appears in the text area under the drop-down. I get the same result if I change the code in template_list.js to:
[
{title: "Name", url: "templates/file1.cfm", description: "Name."},
{title: "Name2", url: "templates/file2.cfm", description: "Name2."},
...
]
...and also if I add quotations around "title", "url", and "description".
Again, sorry if the answer is obvious, but as a beginner I appreciate any help.
Per the documentation the TinyMCE configuration object expects you to pass an array containing one object for each template. At a high level it would look like this:
tinymce.init({
selector: "textarea", // change this value according to your HTML
plugins: "template",
menubar: "insert",
toolbar: "template",
templates: [
{title: 'Item 1', description: 'Desc 1', content: 'My content'},
{title: 'Item 2', description: 'Desc 2', url: 'development.html'}
]
});
You will note that the templates configuration option is passed an array of objects - this is what TinyMCE expects so no matter what you have to return an array of objects.
You can insert the template HTML directly (as shown in the first example above) or you can point to a URL that the browser can fetch when TinyMCE is initialized (as shown in the second example above). There is no template_external_list_url configuration option so that is not working because its not valid.
If you want to externalize the templates outside the TinyMCE configuration you can place the data in a file and reference that via a URL. For example:
tinymce.init({
selector: "textarea", // change this value according to your HTML
plugins: "template",
menubar: "insert",
toolbar: "template",
templates: "/path/to/the/file/templates.php"
});
The URL referenced there must return an array of objects as that is ultimately what TinyMCE is expecting. Your example above seems to imply your external file is returning a JavaScript variable named tinyMCETemplateList - but that means nothing to TinyMCE so while the file may be loaded what is "returned" is not an array of JavaScript objects.
I would suggest you start by getting things to work without externalizing the templates (just make sure you get the basics working). Then externalize the content to a separate file and make sure that the file returns an array of objects. I would note that your example using tinyMCETemplateList seems to return an array of arrays which is not what TinyMCE is expecting.
I found this really frustrating and fiddly to get working at all. Eventually what I'm doing is calling a function in another js file that returns an array that I give to the templates parameter.
function GetTemplateArray()
{
return new Array(
{
title: "2 Columns",
url: "templates/template1.html",
description: "Adds a 2 column table"
},
{
title: "3 Columns",
url: "templates/scf/template2.html",
description: "Adds a 3 column table"
}
);
}
Then in the tinymce.init code:
tinymce.init(
{
...
templates: GetTemplateArray(),
...

Get property from helper return value

So, i have a little handlebars helper, for example
Handlebars.registerHelper('getTest', () => { test: 'test' });
If i call this helper in template, can i use something like this
{{(getTest).test}}
Trying to use different brackets, like with arrays [ ], didn't helped.
I think, it can be done.
Thanks!
In this case we should use {{#with}} helper. So, in my case, final code is
{{#with (getTest)}}
{{test}}
{{/with}}
You might find a helper like this useful if a section of your JSON object contains deeply nested properties, and you want to avoid repeating the parent name.
block helpers docs
As per the Handlebars syntax, you should call your helper as,
{{getTest test}}
Also, consider updating your helper function as below if you just require the helper to return the test value back to the template.
Handlebars.registerHelper('getTest', (val) => {return val});
Tested using http://tryhandlebarsjs.com.
Hope this helps.

TAPi18n: How to show text in several languages side by side?

It seems tapi18n is designed to only have one active language at any given time.
I'm showing a form which includes the same field in several languages. I want to translate the labels and placeholders, because it's useful information for the people filling in the forms, but since I only have access to the current language, I can't show words from others.
I'd like this:
## Description ##
English
[ enter the description ... ]
Español
[ enter the description ... ]
Deutsch
[ enter the description ... ]
to look like this:
## Description ##
English
[ enter the description ... ]
Español
[ introduzca la descripción ... ]
Deutsch
[ placeholder in german... ]
I can think of hacks like creating a pre-processor that copies keys like { "description_placeholder_$$": "introduzca la description" } from each json file to every other json file replacing the $$ to the language code, so each language has all the keys containing $$ from every other language.
Another trick would be to load all the json files into memory, independently from tapi18n, and access the required words directly.
Any more elegant ways to solve this?
As #kyll mentioned, this is how it should work:
TAPi18n.__('amusing spaghetti', { lng: 'ru'});
But it fails to load languages on demand. As a work around, I preload languages on client side and set a session variable to indicate that all languages have been loaded.
var langs = [
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Español' },
{ code: 'de', name: 'Deutsch' }
];
Meteor.startup(function () {
_.each(langs, function(lang) {
TAPi18n._loadLanguage(lang.code).done(function() {
Session.set('langsLoaded',
langs.length == TAPi18n._loaded_languages.length);
});
});
});
Then, in a template I have:
{{trToLang 'amusing spaghetti' 'ru'}}
And finally in a helper:
trToLang: function(key, lang) {
return Session.get('langsLoaded') ? TAPi18n.__(key, { lng: lang }) : '';
}
The session variable is needed because without it sometimes the languages are not loaded before the template renders, and that breaks TAPi18n.
I hope someone posts a more beautiful solution.
Don't know if this is still relevant, but I saw it in use in Sam's md-blog package, maybe it will help to see someone else's implementation?
https://github.com/xolvio/md-blog
HTH

Meteor - TRIPLE template tag is not allowed in an HTML attribute error

I got error message when trying to run existing meteor project.
$meteor
=> Started proxy.
=> Started MongoDB.
=> Errors prevented startup:
While building the application:
client/coinmx.html:169: TRIPLE template tag is not allowed in an HTML attribute
...title="Totals: {{{get...
^
In Meteor 0.8, it's possible to return a Javascript object which is directly rendered into HTML attributes versus earlier versions, where you had to render it yourself.
Old version:
<input name={{name}} title={{title}}>
helpers:
Template.foo.name = "fooName";
Template.foo.title = "fooTitle";
New version:
<input {{attributes}}>
helpers:
Template.foo.attributes = {
name: "fooName",
title: "fooTitle"
};
All of these can be functions, and reactive, etc. Because the object is rendered directly into attributes, there is no need for you to SafeString some manually rendered content as before. This is the recommended way to go if need to render HTML attributes.
See also the following for how conditional attributes work under this scheme:
https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected
The error is pretty much explanatory: you cannot use {{{something}}} inside a HTML attribute, you need to use {{something}} instead. Depending on what the something is (it's not known from your question as you didn't provide the code), that's either all you need to do, or you can achieve similar functionality by returning new Handlebars.SafeString("result") from your helper instead of just "result". However, if you do, you need to be super sure that the thing you'll return won't break the HTML structure.
Hugo's answer above gave me the missing piece I needed for the same issue-- triple stashes in 0.8 no longer supported. Here is an example that hopefully helps.
Where you might have had {{{resolve}}} in your template, you would now do:
<template name='thing'>
<ol>
{{#each all}}
{{resolve}}
{{/each}}
</ol>
<template>
The helper code then makes use of Spacebars.SafeString which looks to be preferred with Blaze:
Template.thing.helpers({
all: function () {
return Things.find();
},
resolve: function () {
var result = "<li>";
for (var i = 0; i < this.arrayOfClassNames.length; ++i)
result += <'div class='" + this.arrayOfClassNames[i] + "'></div>";
result += "</li>";
return new Spacebars.SafeString(result);
}
});
The key here is to return the 'new Spacebars.SafeString(result)' to wrap your HTML (which must be well formed).

Handlebars + Meteor + iron-router

I am using iron-router for my meteor project and everything was going fine but I just ran into some strange behavior.
I have a loop set up for a list of items that looks something like this.
{{#each list_items}}
<div>{{user.username}}
Click here!
</div>
{{/each}}
The JSON object for my user looks something like this:
{
user: {
username: jdoe
},
images: {
low-res-url: http://example.com
},
link: http://example.com/profile
}
Now the {{user.username}} shows up as expected but when I try to put the {{link}} in the href I get an error from iron-router saying
"You called Router.path for a route named undefined but that that route doesn't seem to exist. Are you sure you created it?"
Any help or advice would be appreciated.
Under the hood Iron-Router registers handelbars helper:
Handlebars.registerHelper('link', function (options) {
...
});
Simply change field link to different name like my_link.
As #perhelium mentioned Iron-Router has specified a helper named 'link'
Handlebars.registerHelper('link', function (options) {...});
In order to access an item named 'link' in your JSON object you need to explicitly refer to the JSON object itself.
So your line: Click here!
Would need to be specified as Click here!

Resources