I have a number of hashtables with Integers as keys, and i want to be able to iterate over them in my Freemarker templates, however, nothing seems to work.
I tried the example from Freemarker iterating over hashmap keys:
<#list user.props() as prop>
${prop} = ${user.get(prop)}
</#list>
It probably works with Strings as keys, but it didn't with Integers. I also can't even retrieve the value from my hashtable by the concrete value. What i have is:
Hashtalbe ht = new Hashtable();
ht.put(1, "hello");
datamodel.put("devices", ht);
(datamodel being the hashmap passed to the template).
In the template i do the following:
<#if devices??>
<#list devices?keys as prop>
<p>${prop}</p>
<p>${devices.get(1)}</p>
OR
<p>${devices.get(key)}</p>
OR
<p>${devices[key]}</p>
OR
<p>${devices[1]}</p>
</#list>
<#else>
<p> no devices</p>
</#if>
But none of that works. Can you help me, please?
PS. I converted the hashtable from into to pass it to the template, but that seems like a bit of a workaround.
Best regards,
Timofey
for those of you who may follow my footsteps.
Apparently, FreeMarker can't work with Hashtables with as parameters. So I ended up creating the versions of these hashtables inti and, since i had numbers as keys in my hashtables, i was able to do the following in my template:
<#list 1..100 as prop>
<#if hashtable[prop?string]??>
<option value='${prop}'<#if prop==selected> selected='selected'</#if>>${hashtable[prop?string]}</option>
<#else><#break>
</#if>
</#list>
Good Luck and may the force be with you :)
This is the old issue that FTL's hash type isn't like Java's Map, and it only supports string keys. But, since 2.3.22 you can use someMap?api.get(someNonStringKey) to work that around. It needs some configuring to enable, but nothing that breaks an existing application. See this answer or this FAQ entry.
Related
I have used a lot of the email marketing platforms, but I don't think I am understanding the developer guidelines for using Handlebar.js with SendGrid to use If/Then statements.
I know my way around the code, but the guide isn't clear how to structure the statement for use with their custom fields. It looks like there needs to be some sort of path. Or maybe not. The examples they use don't really help.
https://sendgrid.com/docs/for-developers/sending-email/using-handlebars/#basic-if-else-else-if
I've basically rewritten the code over and over and sent myself some tests. I can get the field to show up without the if-then statement, but other than that its a no go. I have also written tech support, but have not heard back yet. No chat feature :/
{{#if city_code=avl}}
AVL
{{else}}
not avl
{{/if}}
The email only contains the {{else}} part of the code. So in the above example "not avl".
I hope you already found an answer to your question though Sendgrid does not allow to extend Handlebars with extra plug-ins contrary to suggested above.
What you need is the following construct,
{{#equals city_code avl}}
AVL
{{else}}
Not AVL
{{/equals}}
https://sendgrid.com/docs/for-developers/sending-email/using-handlebars/#conditional-statements
{{if anything}} - only check whether anything is truthy or falsy, you cannot compare it to something.
The if statement verify only if the variable is true.
In order to achieve your example, you should create a new helper:
Handlebars.registerHelper("eq", function(a, b, options){
if (a == b) {
return options.fn(this);
}else{
try{
return options.inverse(this);
}catch(e){}
}
});
And your handlebar template will be:
{{#eq city_code avl}}
AVL
{{else}}
not avl
{{/eq}}
The CSS.Pseudo types of csstypes have a bunch of CSS selectors like for ':hover' , ':active' and so on.
Is it possible to create a new type based on CSS.Pseudo, which accepts all the CSS.Pseudo types but with a '&' in front?
For example '&:hover', '&:active' and so on.
I want to be able to do something like
type CSS.Pseudo = ':hover' | ':active' ... etc.
type CssStyle= { [SOMETHINGSOMETHING CSS.Pseudo]: string}
const styles: CssStyle= {
'#:hover: someCssString, //OK
':hover: someCssString, //NOT OK
'&:hov': someCssString //NOT OK
}
I've tried a billion things on TS Playground but I feel I'm just not good enough at TS or it's just impossible.
You can't do this programmatically, at least as of TypeScript 3.5.
This has been suggested before, and the suggestion was closed as a duplicate of either a string literal key augmentation or a regular expression string literal validation suggestion, neither of which are particularly close to being incorporated into the language. If you really want to see this happen, you might want to go to one or both of those issues and give them a 👍 or possibly describe your use case if you think it's more compelling than what's already there.
Sorry this isn't the answer you probably want, but at least you can stop trying to get the compiler to do this for you. Good luck!
I looked at this tutorial: https://spring.io/guides/gs/validating-form-input.
Using th:errors results in <br> separeted error messages. I want to have an unordered list. So I've defined a fragment like this ...
<td th:fragment="validationMessages(field)" th:if="${#fields != null and field != null and #fields.hasErrors(field)}">
<ul>
<li th:each="error : ${#fields.errors(field)}" th:text="${error}"></li>
</ul>
</td>
... and using it with ...
<td th:replace ="form :: validationMessages('age')"></td>
Is there a "clean code" solution / best practice, like overriding the render implementation of th:errors?
You could probably create your own Thymeleaf Processor, based on org.thymeleaf.spring4.processor.attr.SpringErrorsAttrProcessor, that used your own method of delimiting errors, and then use that rather than the one Thymeleaf gives you. It doesn't look particularly designed for extending, though.
I think the way you did it is probably best. I tend to prefer my HTML templates to be in a templating language (like Thymeleaf) rather than in Java code. You can modify as needed (such as adding styling classes) and it's clear what the code does. This is exactly the kind of thing template fragments are made for.
I'm working in Alfresco and I'd like to create my own custom component (for a form) extending an exiting one. In my case "number.ftl".
I'd like to provide the ability to set a defaultValue, so that if field.value is empty the default value will be used
default-number.flt
<#if field.control.params.defaultValue?? && !field.value?has_content>
<#assign field.value=field.control.params.defaultValue>
</#if>
<#include "/org/alfresco/components/form/controls/number.ftl" />
It complains about the dot (.) in field.value:
Caused by: freemarker.core.ParseException: Parsing error in template "org/alfresco/components/form/controls/year.ftl" in line 3, column 23:
Encountered ".", but was expecting one of:
"="
"in"
">"
How do I set the variable?
UPDATE
I've tried as suggested by abarisone (but I can't set the variable after importing "number.ftl" or the old value would be used):
<#if field.control.params.curretYearDefaultValue?? && !field.value?has_content>
<#assign value in field>
${.now?string("yy")}
</#assign>
</#if>
<#include "/org/alfresco/components/form/controls/number.ftl" />
but i get:
FreeMarker template error: For "#assign" namespace: Expected a namespace, but this evaluated to an extended_hash+string (org.alfresco.web.scripts.forms.FormUIGet$Field wrapped into f.e.b.StringModel): ==> field [in template "org/alfresco/components/form/controls/year.ftl" at line 3, column 27]
UPDATE2 (solved)
As suggested by ddekany here a working solution
<#if field.control.params.useCurretYearAsDefaultValue?? && field.control.params.useCurretYearAsDefaultValue = "true" && !field.value?has_content>
${field.setValue(.now?string("yyyy"))!}
</#if>
<#include "/org/alfresco/components/form/controls/number.ftl" />
FreeMarker templates don't support data-model modification. They only meant to read the stuff that was already prepared by Java code. You can set top-level variables only because those aren't part of the data-model (they are in a scope in front of the top-level data-model variables). And so FreeMarker doesn't even have a syntax for modifying a subvariable. But, a back door might exists to achieve what you want. Depending on configuration settings and on what field is on Java-level, ${field.setValue(...)} might works. It's quite a hack to do that, mind you. Manipulating form content from a template, that stinks. You should call out to some Java helper method at least.
If you look at the Freemarker assign reference, you will see that when you use assign you usually write <#assign name=value> where name is the name of the variable. It is not expression.
In fact the compiler complains about the fact it was expecting a "=" or "in".
The latter makes sense if you look further to this:
<#assign name in namespacehash>
capture this
</#assign>
explained like that:
If you know what namespaces are: assign directive creates variables in namespaces. Normally it creates the variable in the current namespace (i.e. in the namespace associated with the template where the tag is). However, if you use in namespacehash then you can create/replace a variable of another namespace than the current namespace. For example, here you create/replace variable bgColor of the namespace used for /mylib.ftl:
<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>
So I can suggest you to import the number.ftl file first and then search for the variable you're wishing to set.
I'm trying to add a prefix to the keys to be translated. This is one of my attempts:
<label for="{{n}}">{{_ 'input_label_{{n}}' }}</label>
<input name="{{n}}" placeholder="{{_ 'input_placeholder_{{n}}' }}">
Obviously it does not work because you can't nest {{ ... }}'s.
I've also tried creating a helper:
{{tr 'input_label' n}}
tr: function(prefix, fieldName) {
return TAPi18next.t(prefix + '_' + fieldName);
}
But it comes back untranslated. I assume because I'm calling TAPi18n as a static and not an instance of it, but I don't know how else to do it.
These are just two of many attempts.
I will have hundreds of inputs, and I want to avoid sending all the translation keys to the input template, since it's redundant information. The key variations can easily be made by adding prefixes.
Can you think of any way to generate the key values dynamically?
Use the second approach, but with TAPi18n.__ rather than TAPi18next.t.
Unlike TAPi18next.t, TAPi18n.__ reactively updates when the user's language choice is changed and the language has finished downloading. I'm guessing the problem is that the language choice hasn't quite come through when the template is first rendered, so TAP18next.t returns the strings in the default language (English), and doesn't update when the language changes. Using TAPi18n.__ instead fixes this.