Featured

Saturday 30 April 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:
  1. Class that implements the Use-interface
  2. Class that extends WCMUse-class
  3. Class that is adaptable from Resource (resource.adaptTo(YourClass))
  4. Class that is adaptable from SlingHttpServletRequest (request.adaptTo(YourClass))
  5. 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 own adapters. 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!!!

SonyCharan

No comments: