April 10, 2020
Estimated Post Reading Time ~

Client Libraries in Action

Let us say you want to create a new website for your Teddy Bear product. You want this side to be attractive and beautiful along with cool features. Most likely, to achieve this you will have to write lots of CSS and JavaScript in your code.

With the complexity of your website, your code complexity will also increase. With this, it becomes more and more difficult to maintain your JavaScript and CSS code. A website made on top of AEM also faces this issue. To combat this, AEM provides a cool feature called Client Libraries.

Client Libraries in AEM

Client libraries allow us to manage our client-side code including JS and CSS and provide options to debug, minify, merge and gzip the client-side code.
  • Go to your project folder in CRXDE and create a node called clientlibs of type cq:ClientLibraryFolder
Create a clientlib
  • Now we need to add the categories for the clientlib. Categories is the identifier used to directly include this clientlib from a content page or to embed it in other clientlibs. We can categorize our clientlibs using this property to manage files easily and only load whatever we need. The categories property, being multi-valued, allows a library folder to be part of more than one category. Add the categories property to the clientlibs node.
                                                Name: Categories     
                                                Type: String[]    
                                                Value: cq.authoring.dialog
  • Create the following structure in clientlibs folder
JS and CSS libs
As you can see, we have created js and css folders (all JS files will go under js folder and all CSS files will go under css folder) along with two text files js.txt and css.txt.
  • Create a new component in your project folder as below
Create a component
  • Create a new node under your component cq:dialog of type nt:unstructured. Now create its children nodes as per the below configuration.
<?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="Client Lib Demo"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/foundation/container">
        <layout
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/foundation/layouts/tabs"
            type="nav"/>
        <items jcr:primaryType="nt:unstructured">
            <tab1
                jcr:primaryType="nt:unstructured"
                jcr:title="Properties"
                sling:resourceType="granite/ui/components/foundation/container">
                <layout
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
                <items jcr:primaryType="nt:unstructured">
                    <columns
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/foundation/container">
                        <items jcr:primaryType="nt:unstructured">
                            <imageSrc
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="cq/gui/components/authoring/dialog/fileupload"
                                autoStart="{Boolean}false"
                                class="cq-droptarget field-bgvalue"
                                fieldDescription="Drag &amp; Drop Image"
                                fieldLabel="Image"
                                fileNameParameter="./imageName"
                                fileReferenceParameter="./imageRef"
                                id="file-upload-special"
                                mimeTypes="[image]"
                                multiple="{Boolean}false"
                                name="./image"
                                title="Image"
                                uploadUrl="${suffix.path}"
                                useHTML5="{Boolean}true"/>
                            <altText
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/foundation/form/textfield"
                                class="field-prereq"
                                fieldDescription="Please describe the image for screen readers."
                                fieldLabel="Alt Text"
                                id="alt-special"
                                name="./altText"
                                validation-error-msg="This field is required when the Image is set."
                                validation-prereq=".field-bgvalue img"
                                validation-prereq-attr="src"/>
                        </items>
                    </columns>
                </items>
            </tab1>
        </items>
    </content>
</jcr:root>
  • This component has one fileupload widget and one textfield. Our goal is to put validation on the Alt text field. We want the Alt Text field should be required only if we author the Image in the fileupload widget.
  • For the validation, we have to write some JS code. Therefore, create a new file named validation.js in the js folder and paste the following code in it.
$(window).adaptTo("foundation-registry").register(
 "foundation.validation.validator", {
  selector: "#alt-special", // validates the specific alt field
  validate: function(el) {
   var $el = $(el);
   var $form = $el.closest('form'); // get the form
   var $upload = $form.find("coral-fileupload[name$=image]"); // find the file upload widget
   if ($upload.hasClass('is-filled') && !$el.val()) { // if class exists, return the validation message
    return "Enter Alt Text";
   } else {
    return;
   }
  }
 });
  • This code searches the required class and if the class is found, then the validation passes and the edit dialog will be saved, otherwise, it won't.
  • Now open the js.txt file and paste the following code in it. 
                                                    #base=js
                                                    validation.js
  • The first line determines the path of the JS files relative to the js.txt.
  • The second line determines the JS file be included in the client library. Each JS file we want to include has to be written in a new line.
  • Now open the dialog and try to save it after authoring image but the Alt Text field is empty. The dialog will not save and show validation error.
Validation error
  • Thus, our client libraries are including. Similarly, we can write CSS and include it in the css.txt.

Other properties in clientlibs

Apart from the few properties discussed in the above section, we have a few other important properties.

dependencies

Let's say clientlibA depends on clientlibB which depends on clientlibC, then on the page which is referring clientlibC, all clientlibA, clientlibB and clientlibC will be included. Thus, dependency property signifies if a one clientlib file depends on others.

embed

For the minifying purpose, AEM will merge all the clienlibs in the current one. If clientlibA embeds clientlibB which further embeds clientlibC, then clientlibA will be loaded by embedding clientlibB's code and clientlibC will not be embedded.

Clientlib configuration

If you navigate to http://<host>:<port>/system/console/configMgr and search for Adobe Granite HTML Library Manager and open it then you will see it has configurations for Minify, Debug, and GZip
Adobe Granite HTML Library Manager
Apart from these basic configurations, we are also provided many other configurations to make clientlibs better. 


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.