Thursday 8 September 2016

Sightly api, comparing, accessing arrays with sightly in AEM


Here we will discuss about:
· How to use arrays with slightly
· How to compare
· How to use API - Some scenarios


Arrays :
Here a sample around arrays:
// accessing a value from properties
${ properties['jcr:title'] }


// printing an array
${ aemComponent.names }


Printing the array, separated by ;
${ aemComponent.names @ join=';' }


// dynamically accessing values
<ul data-sly-list="${aemComponent.names}">
<li>${ properties[ item ]}</li>
</ul>


Comparisons:

Here some use-cases on comparing values


<div data-sly-test="${ properties.jcr:title == 'test'}">TEST</div>
<div data-sly-test="${ properties.jcr:title != 'test'}">NOT TEST</div>


<div data-sly-test="${ properties['jcr:title'].length > 3 }">Title is longer than 3</div>
<div data-sly-test="${ properties['jcr:title'].length >= 0 }">Title is longer or equal to zero </div>


<div data-sly-test="${ properties['jcr:title'].length > aemComponent.MAX_LENGTH }">
Title is longer than the limit of ${aemComponent.MAX_LENGTH}
</div>


Now we will look at the API part and some scenarios here:


Use-API :
In my prvious article I explained that you can call methods from your custom-classes via the data-sly-use notation.
Now explaining, you can also pass in parameters from your components.
<div data-sly-use.aemComponent="${'com.myproject.components.SightlyComponent' @ firstName= 'feike', lastName = 'visser'}">
${aemComponent.fullname}
</div>


Java-code in the Use-Api

public class SightlyComponent extends WCMUse {
// firstName and lastName are available via Bindings
public String getFullname() {
return get("firstName", String.class) + " " + get("lastName", String.class);
}
}


The basic notation of the use-api looks like this is a Sightly component.


<div data-sly-use.mycomp="${ 'com.demo.MyComponent'
@ param1='value1', param2=currentPage}">
${mycomp.calculatedValue}
</div>


In this example you have the following:
the class ‘com.demo.MyComponent’ is instantiated
the name ‘mycomp’ is used
two parameters are passed to the class
the method getCalculatedValue() is called

Now let’s look at the implementation of this; you have 5(!) options to implement this:
Class that implements the Use-interface
Class that extends WCMUse-class
Class that is adaptable from Resource (resource.adaptTo(YourClass))
Class that is adaptable from SlingHttpServletRequest (request.adaptTo(YourClass))
Sling models


Below I will do an example of each option, so you can see what is needed for each.
With all 5 scenarios you can switch the implementation without changing anything in your component.


Scenario-1:
 Class implementing Use-interface
In this case you need to implement init(), and do the all the logic in there. Via the bindings-object you can access all the objects also available on the component.
import io.sightly.java.api.Use;


public class MyComponent implements Use {
private String value;
@Override
public void init(Bindings bindings) {
// all standard objects/binding are available
Resource resource = (Resource) bindings.get("resource");
// parameters are passed as bindings
String param1 = (String) bindings.get("param1");
Page param2 = (Page) bindings.get("param2");
value = param1 + resource.getPath() + param2.getTitle();
}


public String getCalculatedValue() {
return value;
}
}


Scenario-2: Class extending WCMUse
This option is similar like the Use-interface, but has some more helper functionality that you can use. Methods like getResource(), getCurrentPage() etc are already there for you to use.
import com.adobe.cq.sightly.WCMUse;


public class MyComponent extends WCMUse {
private String value;


@Override
public void activate() {
// helper method to get the default bindings
Resource resource = getResource();
// access to the parameters via get()
String param1 = get("param1", String.class);
Page param2 = get("param2", Page.class);
value = param1 + resource.getPath() + param2.getTitle();
}


public String getCalculatedValue() {
return value;
}
}

Scenario-3: Class adaptable from Resource
Code example given here is how to adapt your class from a Resource. Based on that Resource-object you need to pass in the right info to your POJO. In this case you can have a plain POJO without any dependency to AEM or Sightly.
NOTE: In this option you can’t access the parameters
@Component(metatype = true, immediate = true)
@Service
public class MyComponentAdapter implements AdapterFactory {


@Property(name = "adapters")
protected static final String[] ADAPTER_CLASSES = { MyComponent.class.getName() };


@Property(name = "adaptables")
protected static final String[] ADAPTABLE_CLASSES = { Resource.class.getName() };


@Override
public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
if (adaptable instanceof Resource) {
MyComponent comp = new MyComponent();
return (AdapterType) comp;
}
return null;
}
}

Scenario-4: Class adaptable from Request
Like option 3, but now based on the request. Also it is possible here to access the parameters; they are passed in as attributes.
@Component(metatype = true, immediate = true)
@Service
public class MyComponentAdapter implements AdapterFactory {


@Property(name = "adapters")
protected static final String[] ADAPTER_CLASSES = { MyComponent.class.getName() };


@Property(name = "adaptables")
protected static final String[] ADAPTABLE_CLASSES = { SlingHttpServletRequest.class.getName() };


@Override
public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
if (adaptable instanceof SlingHttpServletRequest) {
SlingHttpServletRequest request = (SlingHttpServletRequest) adaptable;
String param1 = (String) request.getAttribute("param1");
Page param2 = (Page) request.getAttribute("param2");
return (AdapterType) new MyComponent();
}
return null;
}
}

Scenario-5: Sling Models
You can technically implement Options 3 and 4 with Apache Sling Models; this saves you from creating your ownadapters. Here’s an example of what that would look like:
@Model(adaptables=Resource.class)
public class MyComponent {


@Inject
private String firstname;
private String value;


@PostConstruct
public void activate() {
value = "calculate " + firstname;
}


public String getCalculatedValue() {
return value;
}
}
Use these test case scenarios and explore slightly !!!




Cheers!!!
Achyuth

No comments:

Post a Comment