In CQ How to disable any field in child page properties dialog? - content-management-system

I have added a new selection type field "Theme" in page properties>Basic.
Now if I add a new page using the same template in WCM, there also I
am getting the option "Theme", which is quite obvious.
Is there any way by which I can hide the field in child page?
P.S this is happening because I am using the same template for the child page.

You can't use the same template and have the page property dialogs be different.
What you can do is overload the dialog
create a new template and corresponding resourceType component that
inherit from your current.
copy the dialog, or tab that you want to be different from the lowest parent of the component. Make sure the dialog is the only node under the component.
Make the changes you want to the dialog.
You would then have to include code in the page jsp to get the parent page property something like:
// if the parent page is always a certain level below the root you can use
// currentPage.getAbsoluteParent(3); to get the third page down from the top
// of the current path tree.
Page parentPage = currentPage.getParent();
ValueMap parentPageProperties;
if (parentPage != null) {
parentPageProperties = parentPage.getProperties();
}
// This tries to get the property 'theme' from the current page. If that fails
// then it tries to get the property from the parent page. If that fails it
// defaults to blank.
theme = properties.get("theme", parentPageProperties.get("theme", ""));

A quick solution would also be to create a second set of template / page component. Let's assume you've got template A, that uses page component B as resource type:
Create template X and play with allowedParents allowedChildren and allowedPaths properties so that the two are exclusive (actual solution depends on your content architecture)
Give X same title as A
Create page component Y that extends B, and defines it's own dialog
Make Y's dialog re-use any tabs from B using xtype=cqinclude (see foundation page's dialog for reference)

Related

AEM Inherited Component Dialog Fields Ordering

In AEM, When I created a dialog which inherit from another dialog I have seen that sometimes the order of the nodes doesn't correspond to the order in which the fields are rendered in the dialog.
Is there a way in which we can specify exactly where a field should be rendered in component dialog?
We can add sling:orderBefore attribute to component dialog field.
Syntax: sling:orderBefore=<--Node-Name-->
Ex: sling:orderBefore="parentPage"
Here parentPage is input field node, Now when you apply sling:orderBefore attribute, then that field will show top of parent page input field.
Thanks for reading.

How can I inherit page properties in AEM 6.2?

In our AEM 6.2 project, I ran to a scenario where I need to config a navigation in one page (let call this Homepage), all of the other pages can use home navigation config or use their own navigation config values.
I decided to use live copy because the clone pages can cancel the linked properties at any time and use their own values. But there is two problem with this approach:
Users must set the template for clone pages by edit their jcr: content/sling:resourceType and jcr: content/cq: template because the navigation is used in all pages and our web uses about 5+ templates.
Live copy does no allowed clone pages are children of source pages. But I was required to make web structure like this :
Home
|_ Page 1
|_ Page 1.1
|_ Page 2
|_ Page 3
Live copy maybe not suitable for this situation, we change to use HTL ${inheritedPageProperties}, this solve the template and structure issue but it creates two new problems:
Inherited properties in property config dialog of child page will be blank (because they are not set and called via ${inheritedPageProperties} )
If users change properties in "Page 1" page, "Page 1.1" (and Page 1.1.1, etc ...) will use these values (Because ${inheritedPageProperties} search the upper nodes to get value).
What our client want are :
All page can use navigation setting only from the homepage or their own page (use home page by default).
If use homepage properties, these values must show in their config dialog.
Try to avoid config template in CRXDE Lite
The website must have the parent-child structure
How can I achieve these requirements?
You can achieve this with a simple Sling Model and Sling's CompositeValueMap
CompositeValueMap docs state:
An implementation of the ValueMap based on two ValueMaps: - One containing the properties - Another one containing the defaults to use in case the properties map does not contain the values. In case you would like to avoid duplicating properties on multiple resources, you can use a CompositeValueMap to get a concatenated map of properties.
We can use this by supplying the descendant's value map (the current page's) then finding the correct ancestor and supplying its properties valuemap as the defaults.
for the purposes of this question, I always assume that 2rd descendant from root is always the ancestor (you can find your ancestor according to your requirnments)
package com.sample.helpers;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.CompositeValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import javax.annotation.PostConstruct;
#Model(adaptables = Resource.class)
public class CustomInheritedPageProperties
{
ValueMap inheritedProperties;
#Self
Resource currentResource;
#OSGiService
PageManager pageManager;
#PostConstruct
protected void init() {
// get the current page, or the "descendant"
Page descendant = pageManager.getContainingPage(currentResource);
/* You have to add your custom logic to get the ancestor page.
* for this question's purposes, I'm always assuming it's the 3rd decendant of root
* more here: https://helpx.adobe.com/experience-manager/6-2/sites/developing/using/reference-materials/javadoc/com/day/cq/wcm/api/Page.html#getParent(int)
*/
Page ancestor = descendant.getParent(2);
// create a CompositeValueMap where the properties are descendant's and the defaults are ancestor's
inheritedProperties = new CompositeValueMap(descendant.getProperties(), ancestor.getProperties());
}
public ValueMap getInheritedProperties()
{
return inheritedProperties;
}
}
Now you can use this as follows
<sly data-sly-use.propHelper="com.sample.helpers.CustomInheritedPageProperties">>/sly>
<!--/* someProp here refers to the property you wish to get (inherited, of course)*/-->
<h1>propHelper.inheritedProperties.someProp</h1>

With setResponsePage, how can I add the page version of the page I want?

With setReponsePage, how can I add the page version of the page I want? So for example 3 in http://localhost:8080/wicket-testing/?3.
Thanks.
You need to use #setResponsePage(Page) instead, not #setResponsePage(Class).
First you need to get a reference to the page with that id: session.getPageManager().getPage(pageId).
Are you confusing wicket pages (where the constructor does not need a wicket-id) with panels (where you have to provide a wicket-id)?
setResponsePage itself accepts either a class (with optional PageParameters) or an instance as a parameter:
setResponsePage(DestinationPage.class);
setResponsePage(DestinationPageWithPageParameters.class, new PageParameters().add("id", 42));
setResponsePage(new DestinationPageWithConstructorParameters(param1, param2));
If you are talking about panels (e.g. MyPanel(String wicketId)) then you need to embed this panel into a wicket page because you cannot pass a panel to setReponsePage.

AEM DefaultValue written to JCR

I noticed that when I set my defaultValue for a dropdown, altho it is correctly selected in the drop down when I first add my component to the page it does not write the defaultValue to the corresponding JCR until I edit the component and save it. Even if I just open the corresponding dialog and click OK now my component works as expected because the values have been added to the JCR.
I am sure there is an important piece that I am missing here, does anyone knows how defaultValues that are required in order for the component to render properly can be added to the JCR when they are first added to the page?
Like Shwan say's that's the way it works. The default values or empty texts are only for the dialog. They aren't persisted until the dialog is authored. The properties have to be set by a different method. CQ already ships with this feature and you can do it without any custom code.
Under your component , create a node called cq:template[nt:unstructured] . If all the data is stored on the component node itself , add the default values as properties to cq:template node with name same as the ones in your dialog. In case the data is stored in a child node add a similar node under cq:template node.
Source : http://blogs.adobe.com/experiencedelivers/experience-management/defaults-in-your-component/
I believe that is simply the way it works. The default value specified in a dialog does not get used until the dialog is loaded/saved, so until that happens the node on the JCR repository that is being authored won't have the default value.
We got around this on a project by adding back-end code that was tied to the component (a tag) so that when the component was loaded, if the property did not exist, it would be written with the default the first time. Ex:
if (wcmMode == WCMMode.EDIT )
{
if(!currentNode.hasProperty("SomePropertyThatWillAlwaysExistIfTheDialogHasBeenSaved")) {
currentNode.setProperty("PropertyThatShouldHaveDefault", GlobalConstants.TRUE);
currentNode.getSession().save();
}
}
Like Sharath Madappa say's that's the way it works fine if component name and jsp name same. If you dont have componentname.jsp under component or page, cq:template won't work.(Reference:http://labs.6dglobal.com/blog/2014-07-08/using-the-cq-template/)
If you hava componentname.html under your component, changed the node [cq:template] type to [cq:Template] instead of [nt:unstructured]. In this case, defaultValues can be added to the JCR when they are first added to the page.

Showing an initially selected object in an ObjectAutoCompleteField on page load in Wicket

I've followed the Wicket by Example guide to get the ObjectAutoCompleteField working, and it does so quite nicely.
I have a huge problem, though, and that is to show an initially set object in the field when the page loads. The object is retrieved from a model I use for the form where the ObjectAutoCompleteField is used. Changing the ObjectAutoCompleteField changes the model attribute it is "connected" to, and any subsequent changes in the field shows the appropriate label in its place, just not the initial one when the page loads—the only thing that shows is the edit link (to get to the autocomplete functionality).
I've looked around in the documentation for the ObjectAutoCompleteBuilder but haven't found any corresponding method to even set the initial value explicitly on page load.
I finally managed to find a solution by looking through the classes relating to ObjectAutoCompleteField.
The ObjectAutoCompleteField is constructed by the build method in ObjectAutoCompleteBuilder. So, by calling the readOnlyRenderer method on the builder, creating a new ObjectReadOnlyRenderer creating a label inside its getObjectRenderer, I got the ObjectAutoCompleteField to render a preselected object on page load.
ObjectAutoCompleteBuilder<Author, Long> builder = new ObjectAutoCompleteBuilder<Author, Long>(provider);
builder.readOnlyRenderer(new ObjectReadOnlyRenderer<Long>() {
public Component getObjectRenderer(String id, IModel<Long> pModel, IModel<String> pSearchTextModel) {
return new Label(id, new PropertyModel<Author>(model, "author"));
}
});
One would think that this was the standard behaviour, but now I know for future reference.