HTL data-sly-test for listChildren - aem

Is there a way to test if listChildren will return anything? Something along the line of: <sly data-sly-test=${item.listChildren.size > 0} />

Assuming this is a followup of Sightly Implicit Objects, the listChildren method will return an Iterator. You can check it’s not empty by calling its hasNext method:
<sly data-sly-test=“${item.listChildren.hasNext}”>

Related

How to access a string array using Sightly(HTL)

How can i access a string array coming from a model class using sightly(HTL)
The TestModel is a model class that returns a string array , getResult() is the getter used to return the string array
how can I use sightly to get it??
<p>display output :</p>
<sly data-sly-use.object = "com.silversea.core.models.TestModel">
<sly data-sly-list.mylist = "${object.Result}"> //what command show we use instead of data-sly-list
<p>1st text: ${item} </p>
</sly>
</sly>
The problem you are facing here is caused by two things:
Defining an identifier on the data-sly-list statement allows you to rename the itemList and item variables. item will become variable and itemList will become variableList
More details in https://docs.adobe.com/content/help/en/experience-manager-htl/using/htl/block-statements.html
So in your example you must change ${item} into ${mylist}
<p>display output :</p>
<sly data-sly-use.object = "com.silversea.core.models.TestModel">
<sly data-sly-list.mylist = "${object.result}"> //what command show we use instead of data-sly-list
<p>1st text: ${mylist} </p>
</sly>
</sly>
The second thing is that you should also follow the java bean naming convention: So if you have a getter getResult() then in HTL you should use ${object.result} (starting from lowercase)

Why does jsx require three dots in this code?

I found a much upvoted answer to a question with the following code:
var condition = true;
return (
<Button {...condition ? {bsStyle: 'success'} : {}} />
);
Why is the ... required? If I omit it, babel complains to me that:
repl: Unexpected token, expected ...
It looks like the spread syntax, but condition is a boolean. I'm having trouble finding docs that explain what is going on.
If you check out MDN: Spread operator:
The spread syntax allows an expression to be expanded in places where
multiple arguments (for function calls) or multiple elements (for
array literals) or multiple variables (for destructuring assignment)
are expected.
If you see, the spread operator inside the jsx syntax to evaluate expression, then
<Button {...condition ? {bsStyle: 'success'} : {}} />
Would become something like, (after babel run with react bootstrap example):
_react2.default.createElement(_reactBootstrap.Button, condition ? { bsStyle: 'success' } : {})
It can also be written as:
<Button bsStyle={condition ? 'success' : ''} />
Which, then means you are passing the props bsStyle with empty string.
So in order to conditionally pass the props itself, you can leverage the spread operator and evaluate the expression. This helps us to pass multiple props on with conditions:
<Button {...condition ? {bsStyle: 'success', bsSize:"large"} : {}} />
Rather than:
<Button bsStyle={condition ? 'success' : ''} bsSize={condition ? 'large' : ''} />
You are using a boolean to return an object. The spread operator ... usage is for spreading that object, so you can make it more readable for yourself by using parenthesis:
var condition = true;
<Button { ...(condition ? {bsStyle: 'success'} : {}) } />
Which is equivalent to this, if your variable is true:
<Button { ...{bsStyle: 'success'} } />
or this one if your variable is false:
<Button { ...{} } />

Binding an html form action to a controller method that takes some parameters

In my Find controller I have a method like:
public Result findLatest(String repoStr) {
............
}
Which is linked through a route:
GET /latest controllers.Find.findLatest(repo: String)
Then, I have a form in a view like:
<form action="#routes.Find.findLatest()" method="get">
....
<select name="repo">....</select>
</form>
But obviously that is failing, because it is expecting some parameters that I do not fulfill in the action. What is the correct way to do this without having to end up leaving the findLatest method taking no parameters in my controller?
You could change the routes to accept an empty string:
GET /latest/:repo controllers.Find.findLatest(repo: String = "")
Then configure your controller function to handle empty string.
That way,
<form action="#routes.Find.findLatest()" method="get">
....
<select name="repo">....</select>
will evaluate repo as an empty string at the controller level.
Edit: Support for this implementation was dropped in Play v 2.1
You may be interested in Play's Optional parameters e.g. play.libs.F.Option[String]
Example: How to handle optional query parameters in Play framework
GET /latest/:repo/:artifact controllers.Find.findLatestArtifact(repo: play.libs.F.Option[String], artifact: play.libs.F.Option[String])
This will allow you flexibility in which arguments need to be provided.
Not sure which language you're using but the link above contains an example for scala and the method declaration in java would look something like:
import play.libs.F.Option;
public static Result findLatestArtifact(Option<String> repo, Option<String> artifact){ ... }
and updated implementation 2.1
Routes with optional parameter - Play 2.1 Scala
EDIT: play 2.1+ Support : Props to #RobertUdah below
Initializing to null:
GET /latest/ controllers.Find.findLatest(repo: String = null)
GET /latest/:repo controllers.Find.findLatest(repo: String)
<form action="#routes.Find.findLatest()" method="get">
Normally all form data go in the body and you can retrieve them in your action method with bindFromRequest() (see docs).
If you really want to pass one form element as a part of the URL then you have to dynamically compose your URL in JavaScript and change your route.
Your route could look like:
GET /latest/:repo controllers.Find.findLatest(repo: String)
And the JavaScript part like (I didn't actually test the code):
<form name="myform" action="javascript:composeUrl();" method="get">
....
<select name="repo">....</select>
</form>
<script>
function submitform() {
var formElement = document.getElementsByName("myform");
var repo = formElement.options[e.selectedIndex].text;
formElement.action = "/lastest/" + repo;
formElement.submit();
}
</script>
Cavice suggested something close to what I consider the best solution for this (since F.Option are not supported anymore with the default binders in Play 2.1 ).
I ended up leaving the route like:
GET /latest controllers.Find.findLatest(repo=null)
and the view like:
<form action="#routes.Find.findLatest(null)" method="get">
<select name="repo"> .... </select>
....
</form>
and in the controller:
public Result findLatest(String repoStr) {
if(repoStr==null) {
repoStr=Form.form().bindFromRequest().get("repo");
.....
This allows me to have a second route like:
GET /latest/:repo controllers.Find.findLatest(repo: String)

Fluid array, if all elements are deleted the array is not empty, but a string

When I have an array in flux:
<flux:form.section name="links" label="Links">
<flux:form.object name="link" label="Link">
<flux:field.input name="linktext" label="Linktext"/>
</flux:form.object>
</flux:form.section>
I first check if the array is set before I render it with fluid:
<f:if condition="{links}">
<ul class="menulinks">
<f:for each="{links}" as="linkelement">
<li>{linkelement.link.linktext}</li>
</f:for>
</ul>
</f:if>
This works. But if there were items set but then deleted, {links} is not empty. It is set as a string with a whitespace " ". And that means the condition in the if-Tag returns true.
And this can lead to an error. In this case I had an error in the backend, but not on the frontend. Even I used nearly the same code in <f:section name="Preview"> and <f:section name="Main">.
My idea was to check the type of {links} and only return true if the type is array. But I am not sure if this is possible with fluid. What other options I have?
The errorreport I see in the backend:
The argument "each" was registered with type "array", but is of type "string" in view helper "TYPO3\CMS\Fluid\ViewHelpers\ForViewHelper"
My idea was to check the type of {links} and only return true if the type is array. But I am not sure if this is possible with fluid.
It is. You can always implement your own ViewHelper if you need support for something, fluid does not bring out of the box. To add the ViewHelper you need, create a php file called IfIsNonEmptyArrayViewHelper.php in some_extension/Classes/ViewHelpers/. The implementation is quite easy:
<?php
namespace Vendor\SomeExtension\ViewHelpers;
class IfIsNonEmptyArrayViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractConditionViewHelper {
/**
* #param mixed $variable
* #return string
*/
public function render($variable) {
if (is_array($variable) && !empty($variable)) {
return $this->renderThenChild();
}
return $this->renderElseChild();
}
}
After that you only have to add your own fluid namespace to your template like this: {namespace ns=Vendor\SomeExtension\ViewHelpers}
Now you can write your condition like this:
<ns:ifIsNonEmptyArray variable="{links}">
<ul class="menulinks">
<f:for each="{links}" as="linkelement">
<li>{linkelement.link.linktext}</li>
</f:for>
</ul>
</ns:ifIsNonEmptyArray>
Of course ns, Vendor and SomeExtension are just placeholders for the real names.

Use Struts if Statement inside iterator

I really need your help. I have the following Struts2 iterator?
<s:iterator value="familiari" status="entry">
</s:iterator>
How can I test the addess propery is empty??
the following does not work
<s:if test="#entry.addess!=''">
</s:if>
It seems you are misundestanding the meaning of the status propery of the iterator tag: that's an special iterator object to track row number (odd/even checks, etc).
You should use the var property. For example (not tested) :
<s:iterator value="familiari" var="myobj">
<s:if test="#myobj.addess != ''">
</s:if>
<s:iterator>