I'm looking into extending the cq5 list component to create custom list displays (obviously). The constructor takes a SlingHttpServletRequest and the minimal java doc says "creates a list from the specified request".
Can someone explain how those request settings are used to build the list? what things in the request should I change to alter the list? Is there better documentation somewhere?
The component uses the request to retrieve the resource object.
In the init method it retrieves a the resource node's properties.
The "listFrom" property should matter for you the most as it controls how the list is created. Either by querybuilder, search, retrieving the children ("children") or tags.
The List component does a simple string equals to find out which option is set and executes the associated logic.
At the end a PageIterator is returned, which is processed by the jsp.
Related
Usually an AEM component is retrieving its data from a JCR node, but I was wondering whether it's possible to pass data to it in HTL. Sure, there's data-sly-resource, but as far as I know this way you can only pass a JCR node.
So in an actual case I've got data in a model that's retrieved from elsewhere. Yet I'd like to use existing components. I'm aware that the data must at least match the component-types' model.
But what if the component I'd like to use is using an model that got its data injected like
#Inject
#Optional
String[] itemList;
So in my stubborn thoughts it should be possible to somehow pass a string array like
<div data-sly-resource="${myModel.aStringArray # resourceType='my/component' }"></div>
But like mentioned above this seems to be meant for passing nodes only.
Is there any way to accomplish passing data directly to a component (other than creating a template)?
You can pass additional information in the form of request attributes or selectors
Selectors
Selectors are the most straight forward of passing simple information. This is an array of strings that can be passed. This is quite useful to data that can act as flags ex:
Variant/Mode of the component
index of the component in a list if it is being included in a loop.
ID of the parent when building things like accordion, tabs
This approach is an abuse of selectors, but IMHO as long as you know what you are doing this shouldn't be a major concern.
<article data-sly-resource="${'path/to/resource' # selectors=['s1', 's2']}"></article>
You can add, replace or remove selectors while including the component. Checkout the documentation for the syntax. https://docs.adobe.com/content/help/en/experience-manager-htl/using/htl/block-statements.html#resource
Request Attributes
This option allows you to add custom request attributes to the component request. This can be used to pass objects as parameters to the component while including them.
These are standard http request attributes with convince of scoping them to a particular instance of script/resource inclusion. To use this you will end up needing a model class or use-js as there is little support to compose the data to be passed along in sightly.
<sly data-sly-use.settings="com.adobe.examples.htl.core.hashmap.Settings"
data-sly-include="${ 'productdetails.html' # requestAttributes=settings.settings}" />
https://docs.adobe.com/content/help/en/experience-manager-htl/using/htl/block-statements.html#request-attributes
There is another way. You can pass additional parameters to the Sling Model on initialization using data-sly-use. For example:
<div data-sly-use.model="${'com.model.Teaser' # test='abc'}"
You can read then the variable "test" in model from request:
#PostConstruct
private void initModel() {
String value = request.getAttribute("test");
// value is 'abc'
}
In order this to work correctly you need to make sure your Sling Model is adaptable from request #Model(adaptables = SlingHttpServletRequest.class}
I am trying to create an auto-generated GUID property on all cq:PageContent nodes. This will be similar to the jcr:uuid property, but will be persisted with content promotion/replication/package installs (whereas the jcr:uuid for a content item changes between different environments).
I am trying to determine how AEM/JCR generates the jcr:uuid property on node creation. The CND defining the property is:
[mix:referenceable]
mixin
- jcr:uuid (string) mandatory autocreated protected initialize
I've tried defining my GUID property in a similar manor, specifying the autocreated and initialize attributes, but this did not result in auto-generation of the property.
Could anybody point me to the source of the jcr:uuid's generation?
As an aside, I asked a related question on the Adobe Community Forum: http://help-forums.adobe.com/content/adobeforums/en/experience-manager-forum/adobe-experience-manager.topic.5_ciot.html/forum__bnxr-i_am_tryingtocreat.html
You don't mention which version of AEM (so whether you're dealing with Jackrabbit or Oak), but the mechanism turns out to be basically the same.
When assigning a default value, there are a few hard-coded system property names that get special treatment (jcr:uuid being one of them). If the name of the property being assigned a default value doesn't match any of the special cases, it falls back the static list of default values from the property definition (e.g. listed in the CND file).
In summary, it looks like you cannot piggy-back on this mechanism to assign your own dynamic default value for an arbitrary property. You would need to implement your own event listener or something.
Jackrabbit: See the implementation of setDefaultValues and computeSystemGeneratedPropertyValues
Oak: See the implementation of TreeUtil autoCreateProperty
In Spring (java) and in .NET also, you can add an object in request scope?
i.e. a user makes a request, you perform some look in a filter or base controller, and then you can add this object into the request object for this current request only
Now in your Action you can check if the key exists and use this object in your action method.
In Play 2 Requests are immutable so you would generally wrap them and pass them around rather than modifying them.
You'd usually use something called action composition to do what you want. Action composition lets you write common code for actions so that you can pre-process a requests and maybe pass the action some data from the request.
Check out the Authenticated example in the docs which provides the action with an AuthenticatedRequest object. The AuthenticatedRequest object wraps the existing Request (rather than modifying it) and adds an additional username value.
As Rich said, you can use Action Composition and, if you want to put more information in Request context, you can use Http.current().args.put("key","value").
I have getResources call:
[[!getResources? &parents=`[[*id]]` &limit=`15` &tpl=`contentsectiontpl` &sortdir=`ASC` &sortby=`menuindex` &includeContent=`1`]]
In a parent resource.
I wish to only display the child resources of this parent, but the above displays both the child resources, and the resources on the same level as the parent.
Does anyone know the correct way to achieve displaying only the child resources without using the parents ID directly?
If youre really getting the parents siblings, you must be specifying the wrong ID. Make sure you shouldnt be using [[+id]] instead of [[*id]], in case youre listing some sort of submenu or such.
Try '-1' for &parents
Comma-delimited list of ids serving as parents. Use -1 to ignore
parents when specifying resources to include. If this is not done,
getResources assumes &parents as the current resource and reads it's
childs from there (plus the resources given in &resources = unexpected
results).
Though it should not be showing the parents sibling resources - I have never seen getResources do this! you are using the call directly in the parent or including it somehow?
If possible you can also hide the parent resource and/or use the hideContainers parameter or possibly the resources parameter to exclude specific [parent] resources.
Do not make this call in Content field in this parent resource - do it in template. The call is correct, must be something else wrong...
You could also specify the template, if it's different between parent and child.
Examples:
&where=`{"template:=":8}`
&where=`{"template:=":1, "OR:template:=":2}`
&where=`{"template:IN":[1,2,3]}`
I'm implementing a Custom Workflow and Activities to be reused in multiple projects and trying to get them to be as easy to use as possible. In this workflow I have a Property whose name is 'UserID' which I'd like to bind to a dependencyproperty in one of my activities. I can currently bind it at design time searching explicitly for the property each time I add one of these activities to the workflow, but I'd like for this activity to be binded automatically.
As far as i know (correct me if I'm wrong), to bind a dependency property at design time I need to specify a string of the form "Activity=NameOfWorkflow, Path=UserID" to the DefaultBindingProperty metadata tag, and I'd like the name of the workflow to be completed in some way. Any way of doing this?
Thanks
I finally managed to achieve this by attaching an ActivityToolboxItem to the Activity, and overriding a method in it that creates the instance shown in the designer. I used an ActivityBind object to bind the dependencyproperty to the workflow's property. To get the instance of the workflow, I just searched for an ancestor to my activity by calling act.Parent until the activity had no parent (and thus was the StateMachineWorkflowActivity itself)