Adobe Experience Manager Blog

AEM concepts, snippets and implementation

Category Archives: Component Development

Toggle Field visibility based on dropdown’s value – Coral 3

0

AEM’s dropdown comes with a simple and useful feature, to toggle visibility of other Dialog fields based on its selection.

An OOTB implementation is available for component “/apps/core/wcm/components/list/v1/list

Let’s quickly check how to configure it (verified on AEM 6.3 with Coral-3 dropdown):

Step 1: Register dropdown that is supposed to show/hide other dialog fields.

Achieved by adding “granite:class” as “cq-dialog-dropdown-showhide”

Show-Hide drodown.PNG

 

Step 2: Identify the target dialog fields

This is achieved in 2 small steps:

  1. Informing dropdown about the class that all target elements would have, i.e :
    • Add a new child node “granite:data” to the dropdown
    • Add property “cq-dialog-dropdown-showhide-target” as “.<some_class_name>” showhidetarget.PNG
  2. Adding the class to all target dropdown fields, i.e:
    • Add “granite:class” as “hide <some_class_name>” to all target dropdown fields.target-granite-class.PNG

 

Step 3: Define dropdown’s value for which to show the target field

This is achieved in 2 small steps:

  1. Add ‘value’ property to all options of the trigger dropdowndropdown-value.PNG
  2. Declare dropdown value for which to display the target dialog field
    • Add a new child node “granite:data” to the dialog field
    • Add property “showhidetargetvalue” as “<required_dropdown_option_value>” 

target-show-value.PNG

 

 

Advertisements

Custom Responsive grid/Layout container

0

A custom responsive layout container can be created by extending the OOTB Responsive Grid (Layout Container).

Please follow the following steps:

Step 1: Copy OOTB Responsive Grid component

OOTB responsive grid’s path: /libs/wcm/foundation/components/responsivegrid

  • Copy the component to the target project
  • Update name for the component.
    • Since, component name would be added by default in the decoration tags, it might help add specific CSS for the container.
  • Update jcr:title & componentGroup to uniquely identify the component.

 

Step 2: Extend OOTB responsive grid

Update sling:resourceSuperType of the custom container as:

sling:resourceSuperType=”wcm/foundation/components/responsivegrid”

Custom Container.PNG

Step 3: Make it responsive 

At this point, the component can added to the pages, but will not be responsive in the Layouting Mode (i.e. resizing the container / containing elements would have no visual effect).

Responsiveness can be achieved by overriding ns.responsive.isResponsiveGrid() of  /libs/cq/gui/components/authoring/clientlibs/editor/js/responsive/responsive.js. Please find the steps below:

  • Create clientlibs (cq:ClientLibraryFolder) below your component.
  • Add a javascript file. It can be added to source sub-folder (type=nt:folder)  below the clientlibs. Add following snippet to the file:
 //Fix to declare custom container as responsive
(function ($, ns, channel, window, undefined) {
    ns.responsive.isResponsiveGrid = function (editable) { 
        return editable.type === 'wcm/foundation/components/responsivegrid' || '/apps/<app_name>/<path_to_custom_container>'; 
    } 
}
(jQuery, Granite.author, jQuery(document), this)); 
  • Add js.txt below clientlibs. Update js.txt with the path to the javascript file.
  • Add ‘cq.authoring.editor’ category to component’s clientlibs

 

Step 4: Update the component with the desired behavior

The component is both available for use & responsive. You can update the component script as per the business requirement. Also, delete the scripts that are not being overwritten. The deleted scripts would be inherited via Sling resource merger

 

Adding responsive CSS for the Custom Responsive Grid

A custom CSS file for various devices can be created similar to OOTB responsive Grid.

 

Configuring breakpoints

To configure breakpoints for the site, follow the steps detailed at Adobe Site

 

Sling Model annotations

0

Creating a Sling Model

Annotation used:

  • @Model: declares a bean as Sling Model.
  • @Inject: Injects resource property into a class variable.
  • @PostConstruct: declares the function which would initialize the bean after deriving information based on business logic. The function is called after the all injections have completed.

Example:

@Model(adaptables = Resource.class)

public class ContactUsModel {

	private String mailAddress;

	private String phoneNumber;

	@Inject
	protected String title;

	@Inject
	protected String officeCode;

	@PostConstruct
	protected void init() {
		// Business logic to transform injected values and assign to bean variables
		// Example: Resolve mailAddress/phoneNumber applicable for the user's region, based on officeCode
	}

	public String getMailAddress(){
		return mailAddress;
	}

	public String getPhoneNumber(){
		return phoneNumber;
	}
}
  • In the above example, ‘adaptables = Resource.class’ maps the sling model against a Sling Resource.
  • The @Inject would inject ‘contacts’ property from the resource into ‘contacts’ class variable. The property value injection occurs after adapting the Resource into Value Map.

 

Optional/Required fields

@Model annotation provides ‘defaultInjectionStrategy’ attribute to indicate if the injected fields in a sling model should be required/optional.

Injection strategy on class level:
  • Use ‘defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL’ to mark all injected fields as optional
  • Use ‘defaultInjectionStrategy = DefaultInjectionStrategy.REQUIRED’ to mark all injected fields as required. Its also the default configuration, if ‘defaultInjectionStrategy’ is not specified.
Injection strategy on Field level:
  • @Required / @Optional annotations can be used to selectively mark fields as required/optional.

Example:

@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ContactUsModel {

	private String mailAddress;

	private String phoneNumber;

	@Inject
	@Required
	protected String title;

	@Inject
	protected String officeCode;

	@PostConstruct
	protected void init() {
		// Business logic to transform the Injected values and assign to bean Variables
		// Example: Resolve mailAddress/phoneNumber applicable for the user's region, based on officeCode
	}

	public String getMailAddress(){
		return mailAddress;
	}

	public String getPhoneNumber(){
		return phoneNumber;
	}
}

Adapt Model from Resource / SlingHttpServletRequest

A Models can be adapted both Resource / SlingHttpServletRequest. This depends upon the fields required to be injected.

  • If only resource properties are required, prefer using:
@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
  •  If Sling Objects (eg. currentStyle, currentPage, xssApi etc) are also required, prefer adapting to SlingHttpServletRequest.
@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)

Default Value

@Default allows to specify default value for fields (including arrays).
Example:
@Inject @Default(values="Contact Us")
private String title;

@Inject @Default(intValues={1,2,3,4})
private int[] integers;

Refer to link, to use attribute names matching with the field’s type.

Alternate field name

Use @Named if the field name is different from the property name

@Inject @Named("jcr:created")
private String created;

Via

To inject field based on JavaBean property of the adaptable. Use with ‘SlingHttpServletRequest’ to inject property value from the resource.
@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ContactUsModel {
    @Inject @Via("resource")
    private String title;
}

Self

Inject adaptable object to a field.
@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ContactUsModel {
    //Accessing the resource that is adapted to ContactusModel
    @Self
    protected Resource resource;
}

Additional Notes

Design Object

The Design object can be accessed on adapting model to Resource / SlingHttpServletRequest

Injecting currentStyle object

Used when the Sling Model is adapted from SlingHttpServletRequest. Example:

@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategyzOPTIONAL)
public class ContactUsModel {
@Inject
private Style currentStyle;
}
Fetch currentStyle object from Resource

Used when the Sling Model is adapted from Resource. Example:

@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ContactUsModel {
   private Style currentStyle;
   private Designer designer;

   @PostConstruct
   protected void init() {

       // Getting the currentStyle from the Designer.class
       designer = this.resourceResolver.adaptTo(Designer.class);
       if (designer != null) {
           currentStyle = designer.getStyle(resource);
       }
    }
}

Inject OSGi Services

OSGi services can be injected via @Inject. The annotation could be used while adapting to both Resource and SlingHttpServletRequest

@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategyzOPTIONAL)
public class ContactUsModel {

    @Inject
    private ResourceResolver resourceResolver;
}