AEM - How to pass data to a component - aem

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}

Related

Number of converter instance for binding in UWP

How many instance does binding creates internally for converters.
<Image x:Uid="DisplayedImageUrl" Style="{StaticResource ImageStyle}"
Source="{Binding DisplayedImageURL, Converter={StaticResource ImageLogoConverter}}" />
How many instance does of ImageLogoConverter will be there?
Is it good idea to use converter in ViewModel, if not then what is the best way to access converted value of ViewModel property.
Is it good idea to use converter in ViewModel?
No. Why would you use a converter in a view model where you can return the converted value directly? Converters are used in the view, typically to convert a non-view friendly value that the view model returns.
If not then what is the best way to access converted value of ViewModel property?
You can simpy return an already converted value from the view model, i.e. instead of binding to a Uri property, you may bind directly to an ImageSource property.
This is the recommnded approach if you for example intend to display a lot of elements in a ItemsControl. Then you probably don't want to invoke a converter for each visible element for performance reasons.
I suppose you created the converter as a resource like this:
The number of instances now depends on the scope where the converter resource is declared. If you create it in <Page.Resources>, one instance will be created to be used by the page. If you create it in App.xaml in <Application.Resources> it will be an application-wide instance. Of course, you can even use a narrower scope - create it as a resource of a single control in your XAML tree for example - in any case, a single instance is created when instance of the parent is created.
The situation gets a bit more interesting if you embed it in a ItemTemplate of a list control. Thanks to virtualization, the system will not actually create one instance for each item. Instead, it will create only so many instances as fit on the screen and they get reused when the user scrolls.
Some MVVM developers don't like value converters, but others use them extensively. It really is a matter of preference. In cas you expect the underlying data to change often, it is advisable to keep the code in the converter as performant as possible as it runs on the UI thread.

Swagger UI generation for generic REST calls

What do I want:
I want to be able to generate swagger documentation that passes a key/value into the URL. This so that I can use generic arguments controller to handle my requests like Dictionary.
If swagger can't generate it, is there a way to generate the documentation by using reflection on my objects? This so that I can still use generic methods
If not, what would be the best way to let everyone know what the correct approach would be.
Why do I want it
I'm developing a new API and I'm using swagger to create the documentation. In this API I want to work with some generic methods to prevent hardcoding things. For example on the PATCH method I use a Dictionary<string, string> to get the property/value combination and in the GET I use a custom object as the argument. In both cases, swagger can't generate the correct parameter fields, because it takes the argument as url key.
Example action & form - incorrect
public async Task<IActionResult> Patch(int id, Dictionary<string, string> viewModel)
{
return await ConnectionWrapper(() => connector.Patch(id, viewModel));
}
This uses the body, not the query
Other examples - incorrect
In the GET I have a model with a custom modelbinder to handle all the rest URL arguments. The problem is because the model is defined it sees the filter as a property.
Then it is in the URL, but it will look like http://example.com/controller/method/id?sort=prop_asc&filter=propTwo%3D=value, instead of http://example.com/controller/method/id?sort=prop_asc&propTwo=value
Desired output
I've modified the HTML to simulate what I would like in the picture above. The URL that would be called would be http://example.com/controller/method/id?propertyName=propertyValue.
I don't mind if there would be only one option to add a generic key/value pair because with it I can demonstrate what I want.
Expected solution
I think the solution lies in the MapType startup method of swagger or in an implementation of the IOperationFilter, but I haven't been able to figure it out.

TypeScript construct class with json

I am building a sample project with Angular2/Typescript in order to use it as a new frontend for an existing backend code.
I really like the ability to create types and consider to use some of the JSON objects served by the backend as typed classes like this:
module DomainObjects {
export class SomeDomainObject {
constructor(attr1:string, attr2:number) {...}
...
}
}
Some of the JSON code that is returned by the backend is very large, so I don't want to work with a huge amount of parameters in the constructor. At best i just pass a JSON object as a single parameter to the constructor which does some checks (or not). On the other hand I'd like to access the JSON object directly. Is something like this possible:
myobject:SomeDomainObject;
...
this.myobject = new SomeDomainObject({id:10,color:'green'});
and access myobject in a template like this
{{myobject.color}}
without having another reference like {{myobject.json.color}}
You can model your JSON data with interfaces (instead of classes). Then you can simply assign the received JSON to it (instead of calling a constructor).
For validation you will most likely need to build a validation function that checks if the received JSONs structure really equals the type that you described in your interface. You could also build a validate and assign function with a signature like
function toTypedData(input: any):SomeDomainObject { ... }
You can also use JSON schema and a suitable validation library to perform that step.

PlayFramework instantiate object in current request scope?

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.
Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>
I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.

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.