I am trying to create a Coral UI 3 multifield and use Sling Models. Here is how the dialog looks like:
Here is the code :
package com.aem.sites.models;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.log4j.Logger;
import com.aem.sites.models.Header;
@Model(adaptables=Resource.class)
public class HeaderList {
final static Logger logger = Logger.getLogger(HeaderList.class);
@Inject
@Named("header")
public Resource headerList;
public List<Header> links;
@PostConstruct
protected void init() {
links = new ArrayList<Header>();
if(headerList != null) {
logger.info("value of header list is "+headerList);
links = populateModel(links, headerList);
}
}
public List<Header> populateModel(List<Header> array, Resource resource) {
if(resource != null) {
Iterator<Resource> linkResource = resource.listChildren();
while(linkResource.hasNext()) {
Header header = linkResource.next().adaptTo(Header.class);
if(header != null) {
array.add(header);
}
}
}
return array;
}
public List<Header> getLinks() {
return links;
}
}
package com.aem.sites.models;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
//Creating adaptable resource class using sling annotation
@Model(adaptables = Resource.class)
public class Header {
@Inject
@Named("linkText")
private String linkText;
@Inject
@Named("linkUrl")
private String linkUrl;
@PostConstruct
protected void init() {
}
public String getTitle() {
return linkText;
}
public String getUrl() {
return linkUrl;
}
public void setTitle(String title) {
linkText = title;
}
public void setUrl(String url) {
linkUrl = url;
}
}
and here is the HTL file:
<header id="header" class="skel-layers-fixed">
<nav id="nav">
<h1><a href="#">Ion</a></h1>
<sly data-sly-use.headerObj="com.aem.sites.models.HeaderList">
<ul data-sly-list="${headerObj.items.listChildren}">
<li><a href="${item.linkUrl @context='styleToken'}">${item.linkText @context='styleToken'}</a></li>
</ul>
</sly>
</nav>
</header>
and here is the error I have been getting :
Caused by: org.apache.sling.models.factory.MissingElementsException: Could not inject all required fields into class com.aem.sites.models.HeaderList
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:593)
at org.apache.sling.models.impl.ModelAdapterFactory.internalCreateModel(ModelAdapterFactory.java:335)
at org.apache.sling.models.impl.ModelAdapterFactory.createModel(ModelAdapterFactory.java:223)
at org.apache.sling.scripting.sightly.models.impl.SlingModelsUseProvider.provide(SlingModelsUseProvider.java:135)
at org.apache.sling.scripting.sightly.impl.engine.extension.use.UseRuntimeExtension.call(UseRuntimeExtension.java:72)
... 209 common frames omitted
Suppressed: org.apache.sling.models.factory.MissingElementException: Could not inject public org.apache.sling.api.resource.Resource com.aem.sites.models.HeaderList.headerList
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:598)
... 213 common frames omitted
Caused by: org.apache.sling.models.factory.ModelClassException: No injector returned a non-null value!
at org.apache.sling.models.impl.ModelAdapterFactory.injectElement(ModelAdapterFactory.java:513)
at org.apache.sling.models.impl.ModelAdapterFactory.createObject(ModelAdapterFactory.java:596)
I am not sure what I am doing wrong here. I am not sure if it has something to do with the dialog ? That's what I suspect.
Any help is appreciated.
Thanks in advance.
The error is thrown because the attribute headerList
in your model cannot be injected successfully. You need to be able to fetch the items
node so that you can then list it's children. Perhaps try the following:
@Model(adaptables=Resource.class)
public class HeaderList {
final static Logger logger = Logger.getLogger(HeaderList.class);
@Inject
@Named("items") <--------- changed this
public Resource headerList;
public List<Header> links;
@PostConstruct
protected void init() {
links = new ArrayList<Header>();
if(headerList != null) {
logger.info("value of header list is "+headerList);
links = populateModel(links, headerList);
}
}
public List<Header> populateModel(List<Header> array, Resource resource) {
if(resource != null) {
Iterator<Resource> linkResource = resource.listChildren();
while(linkResource.hasNext()) {
Header header = linkResource.next().adaptTo(Header.class);
if(header != null) {
array.add(header);
}
}
}
return array;
}
public List<Header> getLinks() {
return links;
}
}
and in your template, just use the links
property:
<sly data-sly-use.headerObj="com.aem.sites.models.HeaderList">
<ul data-sly-list="${headerObj.links}">
<li><a href="${item.linkUrl @context='styleToken'}">${item.linkText @context='styleToken'}</a>
</li>
</ul>
</sly>