How to edit Teaser's Tab options order on AEM? - adobe

I'm (trying) customizing the Teaser component on .content.xml to reach out to my requirements but I don't understand how I can set up an order to tabs options. The best solution would be to write some logic to hide/unhide the Teaser's fields based on the parent component, but I don't know how to do it yet. Meanwhile, I'm editing the XML file.
Options:
Image
Metadata
Text
Link & Actions
The first thing stranger is that I've written the code to show only three options but on AEM Editor keeping showing all options, with "Link & Actions" not declared on .XML. As you can see in the print below.
Path file: ui.apps/.../components/teaser/_cq_dialog/.content.xml
The second thing is that I want to put "Link & Actions" options as the last option on the tab bar. So, how make it?
The following print is my current behavior.

The behaviour you notice is due to Sling's Resource Merger feature. The same feature can be leveraged to achieve everything that you want to do.
To answer your question in parts
You see Links & Actions tab even though you've not defined it in your dialog because your component extends the OOB teaser component and the Sling Resource Merger would merge the options in the parent and the child dialogs to create the final dialog that is presented to the author.
This allows easily extending the features of the parent and only defining the custom properties within your dialog. For e.g. If you only need to add a new tab called Metadata in your teaser component it is enough to just create configurations for that new tab in your custom component and the rest of the configs will flow through from your parent component.
<tabs
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs">
<items jcr:primaryType="nt:unstructured">
<metadata ...>
</items>
</tabs>
You can then use the following properties provided by Sling to further customise the ordering of the properties / tabs or remove / hide some properties.
sling:hideProperties - Specifies the property, or list of properties, to hide. The wildcard * hides all.
sling:hideResource - Indicates whether the resources should be completely hidden, including its children.
sling:hideChildren - Contains the child node, or list of child nodes, to hide. The properties of the node will be maintained. The wildcard * hides all.
sling:orderBefore - Contains the name of the sibling node that the current node should be positioned in front of.
Now to answer your second part, if you want to hide the Links & Actions tab completely in your component, then create a node called actions (same name as parent) and then set the property sling:hideResource to true
<tabs
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs">
<items jcr:primaryType="nt:unstructured">
<metadata ...>
<actions
jcr:primaryType="nt:unstructured"
sling:hideResource="{Boolean}true"/>
</items>
</tabs>
Alternatively, if you don't want it removed but just moved to the end, just create a node called actions and place it after all the other nodes or use the sling:orderBefore property to specify the order of the tabs. An example of order before shown below where metadata tab appears second, followed by text and then links and actions.
<tabs
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs">
<items jcr:primaryType="nt:unstructured">
<metadata
jcr:primaryType="nt:unstructured"
sling:orderBefore="text"
...>
<text
jcr:primaryType="nt:unstructured"
sling:orderBefore="actions"/>
</items>
</tabs>
EDIT: How do you know what tab names to use?:
Sling Resource Merger works when you overlay a component (think of it like inheritance in Java where you are extending another class).
You can overlay an existing component using the property sling:resourceSuperType on the component node. For e.g., this is the screenshot of my teaser component which is overlaying the OOB teaser component core/wcm/components/teaser/v1/teaser.
Since it is not an absolute path, the order of preference for seaching the component in the repository is /libs/ followed by /apps/
So, searching under /libs/ I was able to find the component at /libs/core/wcm/components/teaser/v1/teaser and expanding the dialog showed the following tabs. The same names need to be used in our component to override the position or visibility or any other sling merger features.
I would recommend understanding the inheritance concepts of Sling in general to make it easier working with AEM.

Related

AEM: Component Action Toolbar: Blank style list is visble

We have a component that has a child component, within that, there is another child (child-2) component added. When in author ui, child-2 component does have style icon (in component action toolbar); however clicking on that renders a blank list.
If that child-2 component is added as independent component style icon as well as list (when clicked on) is also visible (with all styles variation as defined in policy).
We tried various ways to debug it but can not. Can anyone please help us here
AEM style system works by defining the styles in the policies. These policies should use the exact path where the component can potentially be placed.
Example: If the component's path is
/apps/project/components/content/myheader then the policy will be defined at path similar to below
/conf/project/settings/wcm/policies/project/components/content/myheader/policy_xxx.
But this policy definition will be used in a path in a template where you would use your component. For example if your template name is templateA and the name of the responsivegrid where your component myheader will be placed is headerGrid then myheader's policy will be used here:
/conf/project/settings/wcm/templates/templateA/policies/jcr:content/headerGrid/project/components/content/myheader <cq:policy property>.
The styles defined in policy will then only be visible in the above responsive grid (parsys in old language). To allow this styles in any other path, in your temlate create the path as required and use the policy there.
Following the above example, if you want your stlyes to be available in a componentA in the TemplateA where componentA is placed in bodyGrid then use the policy here:
/conf/project/settings/wcm/templates/templateA/policies/jcr:content/bodyGrid/componentA/project/components/content/myheader <cq:policy property>.
This should resolve your problem as tested in my system. Unfortunately there is no sandbox public to show you an example.

Storybook Error: Couldn't find story matching 'components-button--page'

I can't seem to resolve this error I am getting in Storybook. I have the following file called Button.stories.mdx:
import { Meta, Story, ArgsTable, Canvas } from '#storybook/addon-docs/blocks';
import Button from './Button';
import ButtonStory from './Button.stories.tsx'
<Meta title="Components/Button" component={Button} />
export const Template = (args) => <Button {...args } />
# Button Component
---
This Button component is supposed to handle all states for a button. It extends off of the HTML button type so that you should have all native HTML features that a button would provide.
We may make some of these optional props required if we deam that it is important. This is usually an accessibility call.
This button should handle actions that occur on the page and if you want to use a href to make it a link you should surround it within an a tag.
Types supported by aero-design-system:
- Primary
- Secondary
## Quick Start
To create a button, use import the `Button` and give it the following props `props`.
<Canvas>
</Canvas>
<ArgsTable of={Button} args={{
backgroundColor: { control: 'color' }
}} />
And I am getting the following error:
Couldn't find story matching 'components-button--page'.
I have tried placing a blank story in there with that ID but that didn't seem to fix anything. I just got a new error
Uncaught Error: Docs-only story
I haven't been able to see anything related to this on here yet.
In my case, the problem was simple, I was trying to load unexisting story:
http://localhost:6006/?path=/story/spoiler--primary
instead, I should've loaded this :)
http://localhost:6006/?path=/story/testcomponent--primary
Something that storybook's documentation doesn't seem to mention is a few important bits:
<Story/> component must have a name property with at least ONE character
<Story/> component must have at least a single child within it
Meaning, the minimum requirement to get the mdx file to render when using the <Story/> component is this:
<Story name="default">
<Button/>
</Story>
This is regardless of whether the <Story/> component is wrapped around the <Canvas/> component or not.
The second half of the problem is <Canvas/> component, and it has just one condition:
It must have at least a single child within it
so the mimimum requirement for <Canvas/> to render is this:
<Canvas>
<Button/>
</Canvas>
Combining everything together for your case scenario, what you need to do with <Canvas/> is this:
<Canvas>
<Story name="default">
<Button/>
</Story>
</Canvas>
Try setting it that way, then refresh the page.
If you are using storybook v6. Try to check stories property at your .storybook/main.js. Make sure the path/file type is correct.
module.exports={
stories:[
'../src/components/Button.stories.mdx', // default page
'../src/**/*.stories.#(js|jsx|ts|tsx|mdx)'
]
}

How to introduce additional fields with default values in AEM Touch UI dialogs?

Situation:
We have an AEM 6.4 Touch UI dialog and a number of existing component instances that were created through this dialog.
Now we want to add an additional boolean property (checkbox) to the dialog.
The default value of the new property should be true / checked.
Expected Result:
When an editor opens the updated dialog for an existing component, I would expect that the dialog shows the new checkbox checked since this is the default and the JCR contains no value for existing components.
Actual Result:
The dialog shows the checkbox unchecked for an existing component that has no value for this property in the JCR.
Surprisingly, the dialog shows the checkbox checked for a freshly created component!
Any ideas? Thanks.
Snippet of the checkbox inside the .content.xml file below.
<newProperty
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
checked="{Boolean}true"
name="./newProperty"
text="The recently added new property"
uncheckedValue="{Boolean}false"
value="{Boolean}true"
/>
It certainly will require a JS validation, since the absence of the value is falsy for the dialog.
Your example should always work, no need for extra js or properties. When you say there is no existing 'value' for this property, do you mean this property is not there or it is empty? Because an empty property would still have a value, in this case an empty string, resulting in it being read as false and the checkbox being empty. A new componenty does not have this property, resulting in the default being shown. If this does not work as designed, could you extend your example by adding all current properties of the component?
#John Goofy - you just need to add below property
'ignoreData={Boolean}true'
then, your node becomes
<newProperty
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
checked="{Boolean}true"
name="./newProperty"
text="The recently added new property"
uncheckedValue="{Boolean}false"
value="{Boolean}true"
ignoreData="{Boolean}true"
/>
please let me know, if it doesn't work for you.

ReactJS: how to access all child components in parent component?

Suppose I've got comments list component with comments components. I wanna implement method that will return all comments components. I assigned to each comment component same ref:
<comments>
<comment ref="myComments" text="abc" />
<comment ref="myComments" text="efg" />
</comments>
I thought I can access all my components by this.refs.myComments but it doesn't work - it returns only last comment component.
What's the correct way to access all comment components?
There is no correct way to do that.
Your view is a representation of your data, so if you want the text for all comments, look at the data.
If you want to update the comments, update the data.
Pulling data out of the view, or manually manipulating the view defeats the purpose of react.

static/private child component in mxml?

Are there any way to declare a child component in mxml which is private/protected or even static?
Sure we can do this inside a script tag, but are there any other way?
Ashier suggests using the "Exclude" metadata tag, but Maskit offers its limitations and suggests alternative solutions:
http://blog.ashier.com/2008/03/25/hiding-properties-in-flex-components/
http://smaskit.blogspot.com/2008/07/making-mxml-subcomponent-private.html
In the strict meaning of these terms, no you can't do that using mxml. The second link posted by Luis contains some workarounds for private/protected behavior.
I found a solution to the static question. I wanted a quick memo pad that could be accessed anywhere in the mobile app, without one instance overwriting edits left open in a different screen.
I created a memo pad mxml control, and then placed it inside a declarations section in the top level application mxml. In each view that I wanted the memo to appear in, I added:
import mx.core.FlexGlobals;
import components.QuickMemo;
private var memo:QuickMemo;
In the view creation complete:
memo = FlexGlobals.topLevelApplication.memo;
In the viewActivation code, I added:
memo.visible = false;
addElement(memo);
In the viewDeactivation code, I included:
removeElement(memo);
The net effect is that only one instance of the memo exists at any time, and that one instance opens in whatever state it existed in the last view it appeared in.

Resources