Deep diving into Sling models PT4

Deep diving into Sling Models PT4

Sling Models part 4: Structure your nodes and build your models
2 July 2020

Part 4: Let Sling do the heavy lifting for you! (Part 2)

In this Sling Models PT4 blog post, I will be showing you some additional things you can do with child resources. You can achieve this using only interfaces, provided that you properly structure your JCR nodes. This is helpful if you’re ever going to build a component using a composite multifield in its dialog.

Structuring your nodes

Let’s say you must develop a component where the authors have to fill in a list of countries and their capitals. The dialog would require you to build a composite multifield that contains 2 text fields. One for the country and the other one for the capital. Technically, you could keep all of these values into two fields (a String array for the countries and a String array for the capitals) and save it on the root node of your component. However, I would recommend that you keep track of this using the following node structure. This will help you organize the data more efficiently.

  • countries-list
    • countries
      • item0: name = Belgium, capital = Brussels
      • item1: name = France, capital = Paris
      • item2: name = United States of America, capital = Washington, D.C.

This way you can be more flexible when you’d have to make changes to your component as well, as you can treat every country as an individual node and make changes to it as you please.

Building your model

In the previous blog post “Let Sling do the heavy lifting for you! (Part 1)”, I talked about how we only have to create an interface if we want to inject simple properties from a node. This behavior also works for injecting child resources.

Let’s build the Sling model for this specific component, just using interfaces:

The parent class:

package com.mycompany.models;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ChildResource;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import java.util.List;
@Model(adaptables = {Resource.class}, resourceType = CountryListModel.RESOURCE_TYPE)
public interface CountryListModel {
    String RESOURCE_TYPE = "mycompany/components/country-list";
    String COUNTRIES_NODE = "countries";
    @ChildResource(injectionStrategy = InjectionStrategy.OPTIONAL, name = COUNTRIES_NODE)
    List<Country> getCountries();
}

The child class:

package com.mycompany.models;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
@Model(adaptables = {Resource.class})
public interface Country {
    String NAME_PROPERTY = "name";
    String CAPITAL_PROPERTY = "capital";
    @ValueMapValue(name = NAME_PROPERTY)
    String getName();
    @ValueMapValue(name = CAPITAL_PROPERTY)
    String getCapital();
}

This is basically everything you need to get it working. If you define a List annotated with @ChildResource, Sling will automatically take all the child nodes of that node you mentioned in the name attribute (in this case “countries”). Sling will adapt them to Country instances. Whenever you call the getCountries() method in HTL, Sling will return those instances.

Keep in mind that @ChildResource works on a relative basis, starting from the current node. If the nodes you want to inject do not reside under a separate child node, but are direct children of the current resource, you can always use “./” to get all of the direct child nodes, but that would mean you might inject more nodes than you truly want. In the previous example, every country is a child of the “countries” child node, so we have to set the name to “countries”. If the nodes you want to display are stored 2 levels deep, you can just use level1Node/level2Node, for example “countries/items”.

And there you have it. You’ve now seen how properly structuring the way you save your data can also save you some time when it comes to development. Keep this in mind the next time you need to build a component using a composite multifield. I hope you found this blog post to be useful and you can apply what you’ve seen here in your daily development. If you still have some questions, feel free to get in touch and we will gladly help you out.

Tip: Digitalum helps organizations to benchmark and advises on tooling architecture. Book time with an expert or contact us.

Need help with your project?

Digitalum, SAP Customer Experience, Cloud, Meet our Team, Contact, E-commerce strategy,

Most recent Insights

Experience Fragments? An Experience Fragment is a powerful feature in Adobe Experience Manager. Imagine creating content pieces like building blocks that you can use over

Lees verder »

“Tell me and I forget. Teach me and I remember. Involve me and I learn.” We adopt a practical approach to learning, inspired by Benjamin

Lees verder »
Data Security and AI

Data security: why is it crucial? Whatever your activities, chances are that you’re collecting and using a lot of confidential data. You’re sitting on a

Lees verder »
SAP Emarsys

Increase customer engagement with SAP Emarsys SAP Emarsys is a customer engagement tool that will help you reach customers with the right message, at just

Lees verder »