currentNode object gives NullPointerException - aem

In my component's JSP, if I want to reference the current node using currentNode object, it throws a NullPointerException and the whole component then throws a ScriptEvaluationException
My component JSP does have the global.jsp included at the top. I guess currentNode object is created by the global.jsp
Strangely, the component throws these exceptions only in a particular site. It works fine in others.
What possible could be the reason for this ? In what conditions does the currentNode object be NULL ?

Maybe your component is a synthetic resource? If you have include tag like this:
<cq:include path="mynode" resourceType="myapp/components/somecomponent" />
and mynode doesn't exist, the included component will be renderer, however you can't referer to the node properties in somecomponent code.
In this case resource variable will be a SyntheticResource and currentNode will be null.
Update:
If you don't really need the currentNode but QueryManager object (as your comment says), you can use resourceResolver object to get it:
resourceResolver.adaptTo(Session.class).getWorkspace().getQueryManager()

I would like to add that the node is created only after the include of the component after drag and drop. So if that is not the case, you will not be having your node inside /content/your-site/

Related

MRTK Add ManipulationHandler in C#

I'm attempting to dynamically add Manipulation Events to a ManipulationHandler that is being added to child objects of a parent. The parent object will be what the user is inspecting, but the user will be able to grab parts off of the parent and inspect them more closely. (i.e. you can look at an engine (parent object), but if you want to inspect the pistons (child objects) you can grab them and look at them)
Instead of having to go into every child object and manually add it in Unity I'd like to be able to add the parent object and just procedurally add the ManipulationHandler and ManipulationEvents on start or awake.
So far I have the following code for adding the ManipulationHandler script, but to add the ManipulationEvent I'm not sure how to set up the pointers so I can use the script and function I want from the source:
gameObject.AddComponent<ManipulationHandler>();
ManipulationHandler handler = gameObject.GetComponent<ManipulationHandler>();
ManipulationEvent newevent = new ManipulationEvent();
ManipulationEventData eventdata = new ManipulationEventData();
eventdata.ManipulationSource = gameObject;
The program works when I grab the objects, but I'd like to add manipulation events when I grab them so I can display additional data.
I see there's a getter and setter for Pointer in ManipulationEventData, but I'm not sure how to instantiate IMixedRealityPointer and how to get it to work. I'm also not sure if that's the object I actually need to accomplish what I'd like to accomplish.
I apologize in advance if I've missed something obvious. I'm new to MRTK.
Thanks!
The ManipulationHandler has four callback events among them OnManipulationStarted and OnManipulationEnded you can simply add listeners to. (see UnityEvent.AddListener)
Unless I understood your question wrong you don't have to instantiate any IMixedRealityPointer. You don't create the event data yourself but rather the ManipulationHandler feeds these events with the current event data including the interacting pointer information. The ManipulationHandler uses OnPointerDown and OnPointerDragged and OnPointerUp via the IMixedRealityPointerHandler interface in order to manage the interacting pointers and invokes the according events where needed.
Instead of using AddComponent followed by GetComponent directly store and use the return value of AddComponent which will be the reference of the newly added Component. MRTK also has an extension method
T EnsureComponent<T>(this Component component) where T : Component
so that you can simply use e.g.
var handler = this.EnsureComponent<ManipulationHandler>();
which internally first checks whether the component already exists, and if not it adds it.
Note that in order to enable near interactions you will also need a NearInteractionGrabbable so you should add this one too.
You also will have to make sure that your objects have some sort of Collider attached to the same GameObject as the NearInteractionGrabbable.
...
gameObject.transform.EnsureComponnet<NearInteractionGrabbable>();
var handler = gameObject.transform.EnsureComponnet<ManipulationHandler>();
handler.OnManipulationStarted.AddListener(HandleOnManipulationStarted);
handler.OnManipulationEnded.AddListener(HandleOnManipulationEnded);
...
/// <summary>
/// If you need it later you need to store the pointer since unfortunately in
/// OnManipulationEnded the <see cref="ManipulationEventData.Pointer"/> is null
/// (no idea why they do it this way :D )
/// </summary>
private IMixedRealityPointer _pointer;
private void HandleOnManipulationStarted(ManipulationEventData eventData)
{
_pointer = eventData.Pointer;
// whatever shall happen when manipulation started
}
private void HandleOnManipulationEnded(ManipulationEventData eventData)
{
// whatever shall happen when manipulation ended
}
Note: I am not sure if this thing you are trying to achieve is possible with this architecture ... it is very possible that nesting various ManipulationHanlder leads to strange behavior here and there. Especially very small parts will be almost impossible to grab ...

AEM - How to pass data to a component

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}

Q: Loading CodeEffects RuleEditor instance with a different source object

I am attempting to load a selected source object from a dropdown menu into the Rule Editor.
I'm already creating the RuleModel from the selected source object in a new instance of the RuleEditor and loading the settings into CodeEffects from the RuleEditor's client settings (calling my LoadSettings function again).
At this point the source object is changed, but the rule fields have not (After selecting a different class, executing rules for the old source object throws this error: No "field" nodes with "x" value of the "y" attribute found)
How to I go about re-rendering the RuleEditor instance in my view?
It turned out to be an unrelated issue with loading one of my source objects: The MaxTypeNestingLevel was set too high and was causing editor.GetClientSettings() to return a string too long for an Ajax post...
I should have checked that first.
Simply calling LoadSettings() after the event that changes the source object is all that's needed.

Extending CQ5 List component

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.

dojo how to query node that has been removed from DOM

From my testing, it appears that dojo's query() function only selects from among elements that are part of a page's DOM.
For example, suppose I have a node named rootNode that has some number of descendents with the class someClass. This code:
var nodeList = query(".someclass", rootNode);
will return an empty NodeList if rootNode has been removed from the DOM (but, of course, if rootNode is part of the DOM, it will return all the nodes with class someClass.
My question: is there a way to use query() in this situation? If not, what is the preferred way for handling this? It looks to me like some of NodeList's methods can be used with a filter(remove and place), but that's not quite the same.
You can get a dojo NodeList as the return result of your dojo.query. Then you can use nodes.map or nodes.every to find the elements you want.
http://dojotoolkit.org/reference-guide/1.9/dojo/NodeList.html
My answer turned out to be very simple: although I didn't find it in the documentation, you can simply call query() on a NodeList. e.g.
var nodeList = query.NodeList();
nodeList.push(rootNode);
var results = nodeList.query(yourSelector);
Note, however: if yourSelector is a unique id and rootNode has been removed from the DOM, it doesn't appear to work. Other types of selectors (class, children, etc) seem to work. I wonder if that's a bug in Dojo...