I have a component that instances 3 or more components.
I need to pass one parameter for each of his sons
Is there a way to do it?
For example a code like this:
<cq:include path="x" resourceType="compo">
<parameter....>
</cq:include>
There is pretty easy solution:
In your main component define variable with request scope
(<c:set var="param" value="10" scope="request" />).
In component,
which you include several times in main one you van use variable
${param}
Related
I have a component that uses two different resources in its HTL/Sightly template.
Is there a way to pass a parameter, to the say in my example the eventResource template, so that I can depending on this passed paramter change a css class on it?
<ul data-sly-list.teasers="${model.resourceList}" class="teaser-list-alternating c-list--reset">
<sly data-sly-test="${teasers.eventTeaser}"
data-sly-resource="${teasers.resource # resourceType='xxx/components/content/eventTeaser'}"></sly>
<li data-sly-test="${teasers.contentTeaser}" class="l-stack l-stack--horse"
data-component-hook-content-hub="teaser"
data-sly-resource="${teasers.resource # resourceType='xxx/components/content/contentHubTeaser'}"></li>
</ul>
I tried using data-sly-resource="${teasers.resource # resourceType='xxx/components/content/eventTeaser', requestAttributes=model.config, selectors='blabla'} to no availability.
#RequestAttribute(name = "contentHub")
private String contentHub;
The requestAttribute contentHub in the eventTeaser model is alway null and I am not sure how to get the selectors value in the eventTeaser template.
I can do it using TypeScript on the front end part but it is not very clean.
I was able to solve it using the selectors indeed and reading the selector value directly from the other sightly template. Here is the documentation I refered to:
data-sly-resource="${teasers.resource # resourceType='xxx/components/content/eventTeaser', requestAttributes=model.config, selectors='inContentHub'}
In the eventTeaser template I then used the following:
data-sly-set.inContentHub="${'inContentHub' == request.requestPathInfo.selectorString}
and depending on the value of the inContentHub variable I was able to change the css class which was my ultimate goal.
Let's say, I have a template A and sling:resourceType is /apps/myproject/components/basePage. In this component I've body.html and header.html and footer.html script included through slightly in body.html.
Now I am creating another template B, and sling:resourceType is /apps/myproject/components/compB and sling:resourceSuperType of compB is /apps/myproject/components/basePage.
In /apps/myproject/components/compB I have added content.html and selector.html
If I create a page (mytest.html) of type template B, then header and footer script is included correctly but when I hit this mytest.selector.html then header and footer script is not included. I want template B will have two different view based on selector.
Please let me know where I am missing.
I believe you are trying to include multiple scripts within same template to achieve different views. This is correct approach todo in AEM. But missing part is the moment you create the second script (selector.html in this case), it becomes another template and you need to code to include your entire page scripts into this script as well.
When you override scripts from /libs/wcm/foundation/components/page component, they ll work fine when your custom script names matches to parent component. For example your body.html will override /libs/wcm/foundation/components/page/body.html and page will render how it is coded. When you create selector.html it becomes independent script as there is no /libs/wcm/foundation/components/page/selector.html.
You need to define all behavior (to include header, footer script etc) explicitly against your custom script. In this case you need include header/footer scripts explicitly into your selector.html
Using a selector means that you're using some special implementation of your component. For instance, your component may have several charts and you want to encapsulate those in your selectors and use it through AJAX from browser, and reuse those selectors in your main component as well.
Currently, you're trying to achieve is to use your header and footer to another component which breaks the encapsulation rule. Rather do this, take out your header.html and footer.html and make those individual components and you it in your basePage as well as your child pages.
See the snippet below:
<div data-sly-resource="${'header' # resourceType='/apps/myproject/components/header'}">
<p>Your body and anything you want to put here</p>
<div data-sly-resource="${'footer' # resourceType='/apps/myproject/components/footer'}">
This way, you can reuse your headers whereever you want even in your selectors.
I am trying to implement something which I hope is relatively straight forward... I have one component (lets call it the wrapper component) which contains another component (lets call it the inner component) inside it via the data-sly-resource tag:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner' }"></div>
I would like to pass in some additional parameters with this tag, specifically a parameter that can be picked up by sightly in the inner component template? I am trying to specify whether the inner templates outer html tag is unwrapped based on a parameter being passed in when the component is called via data-sly-resource.
After experimenting and perusing the sightly documentation, I can't find a way of achieving this.
Does anyone know if this is possible?
Many thanks,
Dave
You can use the Use-API to write and read request attributes if the alternatives proposed here don't work for you.
A quick example of two components where the outer component sets attributes that are then displayed by the inner component:
/apps/siteName/components/
outer/ [cq:Component]
outer.html
inner/ [cq:Component]
inner.html
utils/ [nt:folder]
setAttributes.js
getAttributes.js
/content/outer/ [sling:resourceType=siteName/components/outer]
inner [sling:resourceType=siteName/components/inner]
/apps/siteName/components/outer/outer.html:
<h1>Outer</h1>
<div data-sly-use="${'../utils/setAttributes.js' # foo = 1, bar = 2}"
data-sly-resource="inner"></div>
/apps/siteName/components/inner/inner.html:
<h1>Inner</h1>
<dl data-sly-use.attrs="${'../utils/getAttributes.js' # names = ['foo', 'bar']}"
data-sly-list="${attrs}">
<dt>${item}</dt> <dd>${attrs[item]}</dd>
</dl>
/apps/siteName/components/utils/setAttributes.js:
use(function () {
var i;
for (i in this) {
request.setAttribute(i, this[i]);
}
});
/apps/siteName/components/utils/getAttributes.js:
use(function () {
var o = {}, i, l, name;
for (i = 0, l = this.names.length; i < l; i += 1) {
name = this.names[i];
o[name] = request.getAttribute(name);
}
return o;
});
Resulting output when accessing /content/outer.html:
<h1>Outer</h1>
<div>
<h1>Inner</h1>
<dl>
<dt>bar</dt> <dd>2</dd>
<dt>foo</dt> <dd>1</dd>
</dl>
</div>
As commented by #AlasdairMcLeay, this proposed solution has an issue in case the inner component is included multiple times on the request: the subsequent instances of the component would still see the attributes set initially.
This could be solved by removing the attributes at the moment when they are accessed (in getAttributes.js). But this would then again be a problem in case the inner component is split into multiple Sightly (or JSP) files that all need access to these attributes, because the first file that accesses the request attributes would also remove them.
This could be further worked-around with a flag telling wether the attributes should be removed or not when accessing them... But it also shows why using request attributes is not a good pattern, as it basically consists in using global variables as a way to communicate among components. So consider this as a work-around if the other two solutions proposed here are not an option.
There is a newer feature that request-attributes can be set on data-sly-include and data-sly-resource :
<sly data-sly-include="${ 'something.html' # requestAttributes=amapofattributes}" />
Unfortunately it doesn't seem to be possible to construct a Map with HTL (=Sightly) expressions, and I don't see a way to read a request attribute from HTL, so you still need some Java/Js code for that.
unfortunately, no. there is no way to extend sightly functionality. you cannot add new data-sly attributes or modify existing ones. The best you can do is write your own helper using the USE API
If you just need to wrap or unwrap the html from your inner component in different situations, then you can just keep the html in the component unwrapped, and wrap it only when needed by using the syntax:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner', decorationTagName='div', cssClassName='someClassName'}"></div>
If you need more complex logic, and you need to pass a value to your inner component template, you can use the selectors. The syntax for including the resource with selectors is:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner', selectors='mySelectorName'}"></div>
The syntax to check the selectors in the inner component is:
${'mySelectorName' in request.requestPathInfo.selectorString}"
or
${'mySelectorName' == request.requestPathInfo.selectorString}"
I'm trying to set a class or id parameter on a <h:inputHidden> in JSF. The code looks like this:
<h:inputHidden value="#{getData.name}" class="targ" />
But in the browser, the class isn't set:
<input type="hidden" name="j_idt6" value="j_idt6">
I need to set a class to this parameter, because I have a JavaScript autocomplete function for a <h:inputText> that sets a value in the hidden input, which needs to be passed in the next page.
Any ideas? Thanks!
I know it's a little bit late, but it can help someone in the future.
As inputHidden shows nothing in the browser there's no sense to allow it to have a class.
You can use the Id but as the Id could change as you change the component parents using it would bring some headache.
I'd suggest as a workaround, you can give it a parent so you can manipulate it by javascript.
Exemple:
JSF
<h:panelGroup styleClass="someCssClass">
<h:inputHidden id="someId" value="someValue" />
</h:panelGroup>
Javascript (using jQuery, you could use pure javascript also)
$('.someCssClass input[type=hidden]').val('yourNewValue');
None of these answers here satisfied my needs (need the PrimeFaces component, need class not ID, wrapping is too much work), so here's what I came up with:
Use pass-through attributes: https://www.primefaces.org/jsf-2-2-pass-through-attributes
Use pass:hidden-class="blah" (in my case, it's xmlns:pass up top)
Use [attribute=value] selector:
https://www.w3schools.com/cssref/sel_attribute_value.asp
document.querySelector multiple data-attributes in one element
That basically boils down to using something like this (because h:inputHidden becomes a regular input): document.querySelector("input[hidden-class=" + blah + "]")
Please, see similar question - How can I know the id of a JSF component so I can use in Javascript
You can sed "id" property, but in final html code it can be not the same, but composite: for example, if your input with id="myhidden" is inside form with id="myform", final input will have id="myform:myhidden".
In the end, I used a standard HTML <input type="hidden"> tag, as I had no advantages for using the JSF one. If you're trying to set a value in a hidden input with JavaScript, I recommend using this workaround.
Everybody's aware of passing parameters to a controller via a html form:
<g:form action="save">
<g:textField name="text1" />
</g:form>
And I'm vaguely aware of being able to structure these parameters into some sort of object notation in Grails:
<g:form action="save">
<g:textField name="text.a" />
<g:textField name="text.b" />
</g:form>
With very little idea how they are structured in the controller (objects? hashmaps? I recall having to use .value at some point using the latter example).
So I guess this question is really two questions:
How does Grails handle parameters in object notation like the second example? Can you stick them into arrays too?
What are some other tricks regarding form submission and its parameters that can make forms with very complex and iterative data trivial to handle in the controller? For instance, ATG allows you to bind form fields to beans and walk its entire property graph to find the property you need to set.
The second notation "text.a" is used to disambiguate data conversion from properties to domain objects. For example, if you have 2 domain objects each with a property "a", if you do domObj1.properties = params and domObj2.properties = params the value will go to both domain objects which may not be what you want. So in your view you should have variables domObj1.a and domObj2.a and in your grails controller you can instantiate using def domObj1 = new DomObj1(params["domObj1"])
By your second question if you mean whether you can iterate over objects, you very well can, using GPath syntax in a ${} wrapper, for e.g check out the code in the id property below.
<td><g:remoteLink controller="device" action="getDevice" id="${objInstance.prop1.prop2.id}" update="propDetail">${fieldValue(bean: objInstance.prop1, field: "prop1")}</g:remoteLink></td>
The example above also shows an ajax way of form submission from grails gsp.