I am using Freemarker 2.3.28 in Spring and Freemarker application.
I have a trouble getting booleans working with freemarker macros.
I getting a JSON from server-side which has one attribute as boolean (verified with JS typeof function).
I am putting this data in a template using:
<script id="data-template" type="text/x-handlebars-template">
<#customData var1="{{var_id}}" var2="{{var_label}}" var3="{{var_enabled}}" />
</script>
var3 in this expression is coming as boolean, which I want to use for some checkbox expression to make it checked or unchecked.
Now when I use this as macro-expression as follows, it is not picking the var3 as boolean:
<#macro customData var1 var2 var3>
<div class="checkbox">
<label><input type="checkbox" ${var3?string('checked="true"', ''} />Dummy Label</label>
</div>
</#macro>
I get the error when I use ?string:
FreeMarker template error:
For "...(...)" callee: Expected a method, but this has evaluated to a string (wrapper: f.t.SimpleScalar):
==> var3?string
If I use ?then it gives error:
FreeMarker template error:
For "?then(...)" left-hand operand: Expected a boolean, but this has evaluated to a string (wrapper: f.t.SimpleScalar):
==> var3
I suppose FreeMarker is evaluted before the {{...}} parts, so the FreeMarker macro literally gets "{{var_id}}", which is a string literal. So the basic approach of the problem seems to be incorrect.
Also, even if Handlebars is evaluated first, you end up with things like var3="true", which is again a string literal in FreeMarker, because of the quotation marks around it.
Related
I'm trying to add a button that will link to a different page made to edit/delete an entry. However, the URL in the action /videos/{the id of the video}/edit
Usually I would just put it in curly braces or use a template literal, but these don't seem to be working. When I try using double curly braces /videos/{{the id of the video}}/edit I get an error saying Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead.
I'm trying to pass props for the id of the video to then apply to the URL, but I'm not sure how to go about that.
I've tried template literals, but it gives me a syntax error when I try using those in action="..." so I tried doing what it tells me to do and use binding :id="this.$props.id" but I'm not sure how to then add the id to the URL without still using interpolation.
<form method="get" :id="this.$props.id" action="/videolist/$id/edit">
<button type="submit">Edit</button>
</form>
props: ['id', 'name', 'description', 'category']
Thanks, I ended up solving it using a template literal. It just didn't work how I thought it did. This ended up working
<form method="get" :action="`/videolist/${this.$props.id}/edit`">
<button class="btn btn-success" type="submit">Edit</button>
</form>
In the Sightly templating language, for Adobe AEM6, how do I use a specific class if a condition is true?
${properties.reduceImage} is my checkbox, so if the checkbox is checked then add the class if not then it doesn't return anything. I'm not sure if I'm doing this the correct way.
<div data-sly-test="${properties.reduceImage}" data-sly-unwrap>
<div class="reduce-image">
</div>
</div>
The expression language of Sightly has a few operators that allow to do things like that.
In your case, you have two possibilities: the conditional operator, or the logical AND (&&) operator.
Conditional operator
This operator works like data-sly-test, but at the level of the expression. What is before the question mark (?) is the condition, and then come two parts, separated with a column (:). The first part is the output if the condition is true, and the second part is the output if the condition is false (which we leave empty in your example).
<div class="${properties.reduceImage ? 'reduce-image' : ''}">
</div>
Logical AND operator
This writing is a bit shorter, but also less explicit in it's intention. It uses the fact that like in JavaScript, ${value1 && value2} returns value1 if it is falsy (e.g. false, or an empty string), otherwise it returns value2:
<div class="${properties.reduceImage && 'reduce-image'}">
</div>
In both examples the class attribute will be removed altogether if the corresponding condition is false, because Sightly does remove all attributes with expression that end up being empty or false.
Here's the full documentation of Sightly's expression language:
http://docs.adobe.com/docs/en/aem/6-1/develop/sightly/expression-language.html
In the Sightly templating language, for Adobe AEM6 (CQ), how do I add an attribute to an element only if a condition is true, without duplicating lots of code/logic?
e.g.
<ul data-sly-list="${items}" ${if condition1} class="selected"${/if}>
<li${if condition2} class="selected"${/if}>
Lots of other code here
</li>
</ul>
When setting HTML attributes dynamically (with an expression), Sightly guesses your intention to simplify the writing:
If the value is an empty string or if it is the false boolean, then the attribute gets remove altogether.
For instance <p class="${''}">Hi</p> and <p class="${false}">Hi</p> render just <p>Hi</p>.
If the value is the true boolean, then the attribute is written as a boolean HTML attribute (i.e. without attribute value, like for e.g. the checked, selected, or disabled form attributes).
For instance <input type="checkbox" checked="${true}"> renders <input type="checkbox" checked>.
You can then use two Sightly operators to achieve what you want (both work as in JavaScript): the ternary conditional operator, or the logical AND (&&) operator.
Ternary conditional operator
<ul data-sly-list="${items}" class="${condition1 ? 'selected' : ''}">
<li class="${condition2 ? 'selected' : ''}">
Lots of other markup here
</li>
</ul>
Logical AND operator
For that, you additionally have to understand that like in JavaScript, ${value1 && value2} returns value1 if it is falsy (e.g. false, or an empty string), otherwise it returns value2:
<ul data-sly-list="${items}" class="${condition1 && 'selected'}">
<li class="${condition2 && 'selected'}">
Lots of other markup here
</li>
</ul>
As said, in both examples the class attribute will be removed altogether if the corresponding condition is false.
What Gabriel has said is entirely correct. I did want to add a "gotcha" to look out for though. For the record, I was running into the exact same problem where, in a Sightly template, I wanted to toggle the presence of an input element's "checked" attribute based on a boolean value. In my case this boolean value was coming from the backing Use class.
After about 3-4 hours and being on the verge of pulling my hair out I finally realized that the boolean value I was relying on for toggling the "checked" attribute was ultimately being set in the activate method of a Sling service I wrote to back the work I'm doing. While everything else was logically correct, because I was setting this boolean in activate() and then retrieving it via a getter as needed, it would only ever have its value updated on bundle activation meaning my view would essentially lose state after the first refresh of the page.
I know it's silly but I wanted to call it out since it's relevant here and it may help someone not have to lose some hair like I did...
I'm working on a bigger project with AngularJS. Therefore, I want to make the work for a single form as easy as possible. As we're also using bootstrap, the code for a single input field in a form is quite verbose, maybe like
<div class="control-group">
<label class="control-label" for="inputEmail">Email</label>
<div class="controls">
<input type="text" id="inputEmail" placeholder="Email">
</div>
</div>
If I could write a single tag like
<custom-input
label="Email"
name="inputEmail"
placeholder="Email"
type="text"
... >
</custom-input>
instead, this would help to keep the code clean and the work simple.
To achive this, I'm working on a custom AngularJS directive. My directive currently uses a template similar to the bootstrap example from above, automatically assigning the label to the input-tag. Also, the directive's compiler function moves all attributes from the custom-input tag to the real input-tag in order to make it easy to customize the custom-input tag.
app.directive('customInput', function() {
return {
require: 'ngModel',
restrict: 'E',
template: '<div>' +
'<label for="{{ name }}">the label</label>' +
'<input id="{{ name }}" ng-model="ngModel" />' +
'</div>',
scope: {
ngModel: '=',
name: '#name',
},
replace: true,
compile: function (tElement, tAttrs, transclude) {
var tInput = tElement.find('input');
// Move the attributed given to 'custom-input'
// to the real input field
angular.forEach(tAttrs, function(value, key) {
if (key.charAt(0) == '$')
return;
tInput.attr(key, value);
tInput.parent().removeAttr(key);
});
return;
},
};
});
On Stack Overflow, there are many questions regarding the creation of custom input fields, but they are concerned with the data binding, custom formatting or binding to ng-repeat.
My approach however has a different issue: while the data binding works correctly, Angular's integrated form validation module get confused when the input field is 'required'. For some reason, validation doesn't recognize the new input field and instead keeps the form invalid because of some dead reference, which has an empty value. Please see the minimal example.
Where does the dead reference come from? How can I update the validation-module's references? Is there a better way to achieve my overall goal?
As a boolean attribute, there is a corresponding required property that is still true on your div even if the attribute is moved.
The required attribute isn't getting moved, it must be getting skipped because there is no value. I don't know how to even add it to an element using javascript without a value, but using the form required="required" fixes that
Using transclude=true will use a copy of your element after the compile phase when you moved attributes, I think this keeps the required property from being set
You have to assign a higher priority for some reason, maybe because of ng-model, which is not removed from your div because the name in tattrs is ngModel (although removing from the div doesn't remove the need for priority)
http://plnkr.co/edit/5bg8ewYSAr2ka9rH1pfE?p=preview
All I did was change the required attribute to be required="required" and add these two lines to the directive declaration:
transclude: true,
priority: 10,
I put ng-transclude on the template label by the way so the contents of your element will go in the label and you don't have to have an attribute for that.
I'm trying to pass a form field of type "file" to a CFFUNCTION. The argument type is "any". Here is the syntax I am trying to use (pseudocode):
<cfloop from="1" to="5" index="i">
<cfset fieldname = "attachment" & i />
<cfinvoke component="myComponent" method="attachFile">
<cfinvokeargument name="attachment" value="#FORM[fieldname]#" />
</cfinvoke>
</cfloop>
The loop is being done because there are five form fields named "attachment1", "attachment2", et al.
This throws an exception in the function:
coldfusion.tagext.io.FileTag$FormFileNotFoundException: The form field C:\ColdFusion8\...\neotmp25080.tmp did not contain a file.
However, this syntax DOES work:
<cfloop from="1" to="5" index="i">
<cfinvoke component="myComponent" method="attachFile">
<cfinvokeargument name="attachment" value="FORM.attachment#i#" />
</cfinvoke>
</cfloop>
I don't like writing code like that in the second example. It just seems like bad practice to me.
So, can anyone tell me how to use structure syntax to properly pass a file type form field to a CFFUNCTION??
In your first codesnippet the value #FORM[fieldname]# evaluates to the name of the file uploaded. So you are sending the filename to your function instead of the name of the field containing the filename.
If you want to stick with the structure notation you might use
<cfinvokeargument name="attachment" value="FORM['#fieldname#']" />
or
<cfinvokeargument name="attachment" value="FORM.#fieldname#" />
instead. I also don't think that there is anything wrong with your (working) second code example.
Edit:
It seems as if <cffile> can not evaluate the filefield if you pass the field using the struct notation, due to some auto evaluation magic of the parameter. After some further investigations I found out that passing only the name of the formfield without the form prefix would also work.
<cfinvokeargument name="attachment" value="#fieldname#" />
The filefield parameter is documented as string, containing the name of the formfield without prefix. My last approach seems more "right" to me. It would even hide the implementation a little bit more. I'm also not so much about composing scope/struct var/keys outside of a component or function and then passing it into the function. This should better be done in the function itself.