Monday 8 July 2019

Nested Multifield (coral 3) with Sling Model in AEM

Create AEM multi module project using archtype 11
Create a new component with cq:dialog for Touch UI as shown below.


<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Country Details"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
        <items jcr:primaryType="nt:unstructured">
            <column
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/container">
                <items jcr:primaryType="nt:unstructured">
                    <countries
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                        composite="{Boolean}true"
                        fieldLabel="Countries">
                        <field
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/container"
                            name="./countries">
                            <items jcr:primaryType="nt:unstructured">
                                <column
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/container">
                                    <items jcr:primaryType="nt:unstructured">
                                        <countryName
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                            fieldLabel="Country Name"
                                            name="./countryName"/>                                        
                                        <states
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                                            composite="{Boolean}true"
                                            fieldLabel="States">
                                            <field
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/coral/foundation/container"
                                                name="./states">
                                                <items jcr:primaryType="nt:unstructured">
                                                    <column
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:resourceType="granite/ui/components/coral/foundation/container">
                                                        <items jcr:primaryType="nt:unstructured">
                                                            <stateName
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                                fieldLabel="State Name"
                                                                name="./stateName"/>
                                                            <statePostal
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                                fieldLabel="State Postal"
                                                                name="./statePostal"/>
                                                            <statePopulation
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/numberfield"
                                                                fieldLabel="State Population"
                                                                name="./statePopulation"/>
                                                            <stateDensity
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/select"
                                                                fieldDescription="Select State Density"
                                                                fieldLabel="State Density"
                                                                name="./stateDensity">
                                                                <items jcr:primaryType="nt:unstructured">
                                                                    <high
                                                                        jcr:primaryType="nt:unstructured"
                                                                        text="High"
                                                                        value="high"/>
                                                                    <medium
                                                                        jcr:primaryType="nt:unstructured"
                                                                        text="Medium"
                                                                        value="medium"/>
                                                                    <low
                                                                        jcr:primaryType="nt:unstructured"
                                                                        text="Low"
                                                                        value="low"/>                                                                    
                                                                </items>
                                                            </stateDensity>
                                                        </items>
                                                    </column>
                                                </items>
                                            </field>
                                        </states>
                                    </items>
                                </column>
                            </items>
                        </field>
                    </countries>
                </items>
            </column>
        </items>
    </content>
</jcr:root>



Now create slingmodels to get the authored values.
  1. CountriesModel.java
  2. Country.java
  3. State.java

CountriesModel.java


package com.aemquickstart.core.models;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.ArrayList;
import java.util.List;


@Model(adaptables = Resource.class)
public class CountriesModel {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Inject
    @Named("sling:resourceType")
    @Default(values = "No resourceType")
    protected String resourceType;

    @Inject
    @Optional
    private List<Resource> countries;

    private List<Country> countriesList = new ArrayList<>();

 public List<Country> getCountriesList() {
  return countriesList;
 }

 public void setCountriesList(List<Country> countriesList) {
  this.countriesList = countriesList;
 }
 @PostConstruct
    protected void init() {
        logger.debug("In init of CountriesModel");
        if (!countries.isEmpty()) {
            for (Resource resource : countries) {
                Country student = resource.adaptTo(Country.class);
                countriesList.add(student);
            }
        }
    }
 
}

Country.java

package com.aemquickstart.core.models;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The type Country.
 */
@Model(adaptables = Resource.class)
public class Country {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Inject
    @Optional
    private String stateName;

    @Inject
    @Optional
    private List<Resource> states;

    @Optional
    private List<State> stateList = new ArrayList<>();

    
    public List<State> getStateList() {
        return stateList;
    }

    public String getStateName() {
  return stateName;
 }

 public void setStateName(String stateName) {
  this.stateName = stateName;
 }

 public void setStateList(List<State> stateList) {
        this.stateList = stateList;
    }


    @PostConstruct
    protected void init() {
        logger.debug("In init method of Country model.");
        if(!states.isEmpty()) {
            for (Resource resource : states) {
                State state = resource.adaptTo(State.class);
                stateList.add(state);
            }
        }
    }

}

State.java


package com.aemquickstart.core.models;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

@Model(adaptables = Resource.class)
public class State {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Inject
    @Optional
    private String stateDensity;

    @Inject
    @Optional
    private String statePopulation;

    @Inject
    @Optional
    private String stateName;

    @Inject
    @Optional
    private String statePostal;

 public String getStateDensity() {
  return stateDensity;
 }


 public void setStateDensity(String stateDensity) {
  this.stateDensity = stateDensity;
 }


 public String getStatePopulation() {
  return statePopulation;
 }


 public void setStatePopulation(String statePopulation) {
  this.statePopulation = statePopulation;
 }


 public String getStateName() {
  return stateName;
 }


 public void setStateName(String stateName) {
  this.stateName = stateName;
 }


 public String getStatePostal() {
  return statePostal;
 }


 public void setStatePostal(String statePostal) {
  this.statePostal = statePostal;
 }


 public Logger getLogger() {
  return logger;
 }

    @PostConstruct
    protected void init() {
        logger.debug("In init of State Model");
    }

}




Add below html code in CountryDetails.html

<div>
    <b>Countries Details</b>
    <br><br>
    <div data-sly-use.countryModel="com.aemquickstart.core.models.CountriesModel" data-sly-unwrap>
        <div data-sly-test="${!countryModel || wcmmode.edit}">
            Add country and state details using component dialog
        </div>

        <div data-sly-test="${countryModel.countriesList}">
            <div data-sly-list.country="${countryModel.countriesList}">
                <div>
                    <div>Country Name: ${country.countryName}</div>
                    <br>
                    <div data-sly-list.state="${country.stateList}" style="margin-left:40px">
                        <div>State No.: ${stateList.count}</b></div>
                        <div>Name: ${state.stateName}</b></div>
                        <div>Postal: ${state.statePostal}</div>
                        <div>Population: ${state.statePopulation}</div>
                        <div>Density: ${state.stateDensity}</div>
                        <br>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Deploy code using below maven command.


mvn clean install -PautoInstallPackage


Author CountryDetails component in touch dialog.

Authored details are visible on the page.



3 comments :

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thanks Kishore, This helped me a lot to learn Sling models well.

    ReplyDelete
  3. Thank you Kishore for such a clear explanation.

    ReplyDelete