0

I've been working on a component and currently I'm trying to do different things based on the selector chosen for the component.

So basically if I have a component with this structure

myComponent/
  dialog.xml
  myComponent.jsp
  altView.jsp

I know that if I have a Node with resourceType myComponent I can request the alt view via browser by requesting "path/to/component/content.altView.html" and everything is hunky dory.

Similarly I can do a cq include and do something like:

# with cq include
<cq:include path="my/path.altView" resourceType="myComponent"/>

# or with sling include
<sling:include path="my/path" resourceType="myComponent"  replaceSelectors="altView"/>

However, when I'm handling the request, I've seen some interesting behavior when looking at the RequestPathInfo Object.

For example, if we look at all 3 of the above cases I might have something like this:

# http://path/to/component/content.altView.html
slingRequest.getRequestPathInfo().getSelectors(); // {altView}
slingRequest.getRequestPathInfo().getExtension(); // html

# <sling:include path="my/path" resourceType="myComponent"  replaceSelectors="altView"/>
slingRequest.getRequestPathInfo().getSelectors(); // {altView}
slingRequest.getRequestPathInfo().getExtension(); // html

# <cq:include path="my/path.altView" resourceType="myComponent"/>
slingRequest.getRequestPathInfo().getSelectors(); // []
slingRequest.getRequestPathInfo().getExtension(); // altView

I understand why the cq:include returns different results (we're making a request to my/path.altView and .altView coincidentally serves as the extension in this case). I'm curious if there is a normalized why to pull "altView" (or the selected view) regardless of if it's been used as an extension or selector. Or if this is normal and I just need to check both the extensions and selectors individually.

i.e

selectors = get selectors();
if selectors
   do stuff
else check extensions
   do stuff

Again thank you very much for your insights, this community is awesome.

[EDIT]

In response to an answer, I thought I'd give a little more context to what I'm doing. Basically our component structure is set up so that each of our components has an associated Java Class that handles the business logic. (I.E. apps/myapp/components/myComponent will map to com.mypackage.components.MyComponent) That said, within my component's Class I need to handle the control flow differently depending on how the component was called (i.e. what selectors/extensions/etc). For example, if my component was called normally I'd do the base behavior, but if it was called with selector (for exmaple) "altView" I would need to handle the alternative view differently, and in this alternative view different data will be available, etc.

My question was along the basis that it seems that i can give the "path" attribute of a "cq:include" tag the selector I want to use:

<cq:include path="my/path.altView" resourceType="myComponent"/>

However, when I check my RequestPathInfo in my component class to decide workflow, "altView" is returned as the extension, not within the String[] selectors. Note, the above compiles fine, and it selectors the correct .jsp file for rendering, the RequestPathInfo object just stores the data in a different place.

I'm starting to guess that places the selector into the path attribute works because the selectors and extensions modifiers alter the behavior vary similarly. mycomponent.altView.html resolves to altView.jsp whereas if I was to do mycomponent.altView it would also attempt to resolve a mycomponent/altView.jsp just as it would do the same for mycomponent.xml to mycomponent/XML.jsp

Community
  • 1
  • 1
Brodie
  • 8,399
  • 8
  • 35
  • 55

2 Answers2

4

It seems like you're kind of working around Sling resolution. The easiest way to do "different things based on selector" in a given component (let's say my/new/component) is to create different renderers.

For example, say I am requesting /content/app/page.html, and on that page was the component my/new/component. Or if I request /content/app/page.selector.html, I want a slightly different experience for my/new/component.

In the cq:component, I would create two JSPs: component.jsp and component.selector.jsp. Sling will automatically know, based on the selector in the request, which renderer to use. Obviously each renderer can produce a different experience.

The same is true for extension. In the example, component.jsp and component.selector.jsp are actually equivalent to component.HTML.jsp and component.selector.HTML.jsp. The HTML is just implied. However, you could do component.XML.jsp and component.selector.XML.jsp and Sling will again, pick the most relevant selector, based on the selector(s) and extension of the request.

Now, what if you don't want the selector to show up in the page request's URL (in my opinion you shouldn't)...

You can include your component using sling:include and add the selector, like you've done.

The caveat is that sling:include works a little differently than cq:include, so only use this when you need to. Instead, you could also use Sling mapping to hide the selector from the user. The majority of the time I would recommend this approach.

I'm not sure what you were trying to do with adding the selector to the "path" attribute. I don't think that would do anything. The "path" is defining the resource name (and the node name if the resource is not synthetic). Including the selector in that wouldn't do anything, except make the resource name include a period and the selector.

ryanlunka
  • 236
  • 1
  • 8
  • thanks for this. However, I think my question was about something a little different. Big kudos for the link to the synthetic resource, I have a few cases where that could come in handy. I was actually curious about the concept of a "synthetic" or "mock" resource and how that could be leveraged. – Brodie May 09 '14 at 14:42
  • Now I'm curious. What did I misunderstand about your question? – ryanlunka May 09 '14 at 19:58
  • I was curious why and both used myRes/altView.jsp to render, even though when checking the RequestPathInfo object, cq:include has altView as the extension, but sling:include has it in the selectors list. I was curious if cq:include was doing something special. However, I think I was losing site of the fact that both selectors and extensions are valid when using them to target a certain jsp for render. (sorry it's a lot to fit into a comment) – Brodie May 13 '14 at 16:27
2

My question was along the basis that it seems that i can give the "path" attribute of a "cq:include" tag the selector I want to use:

<cq:include path="my/path.altView" resourceType="myComponent"/> However, when I check my RequestPathInfo in my component class to

decide workflow, "altView" is returned as the extension, not within the String[] selectors.

As opposed to the cq:include tag, you could alternatively use sling:include tag, which provides attributes to modify the selectors & suffix on the request:

<sling:include resourceType="myComponent" path="my/path" addSelectors="altView"/>

or

<sling:include resourceType="myComponent" path="my/path" replaceSelectors="altView"/>

If you already have selectors on the request that you don't want to apply to myComponent.


In terms of the differences between Sling include & CQ include, there seems to be very little, apart from the latter also supporting script inclusion. From the docs:

Should you use <cq:include> or <sling:include>?

  • When developing AEM components, Adobe recommends that you use <cq:include>.
  • <cq:include> allows you to directly include script files by their name when using the script attribute. This takes component and resource type inheritance into account, and is often simpler than strict adherence to Sling's script resolution using selectors and extensions.
anotherdave
  • 6,656
  • 4
  • 34
  • 65