The "AEM Projects" Tab Part 2: Building Widgets

Adam Berberich, January 4, 2017

Building Widgets for your Custom Project

Hey AEM Fans, Adam here again with Part 2 of our multi-part series on the “Projects” tab in Adobe Experience Manager. If you’ll recall back in Part 1 you built your own project template step by step and it was A LOT of fun, but we didn’t dive much further down the rabbit hole. In this post we are going to dive in a little deeper and learn how to create your own custom widgets to be used inside your custom project template. If you haven’t read Part 1 go ahead and browse over there now and follow along as it’s a prerequisite for Part 2.

To get started let’s go ahead and create the folder structure necessary for creating your own custom widget. The structure I like to use is, “apps/cq/gui/components/projects/admin/pod/{nameOfWidget}/{nameOfWidget}.jsp”. It’s worth noting that this path is completely up to you. I however like to use this path as it mirrors the one used by Adobe and is nice to have as a helpful reminder as to where you can find their widgets at when browsing CRXDE Lite. It’s also worth noting that Adobe calls these “Pods”, I call them widgets because I feel like it’s more representative of what they are. You call them whatever you want because you are a freethinking, smart and resourceful AEM developer! folder structure.png

Now it’s time to get down to my favorite part of these posts, the code. You’ll notice the file that is housed in the folder is our good friend JSP. While sightly runs the show when it comes to component development, JSP is still the standard that Adobe is using to build their own widgets/“pods” and since Adobe likes to build them with JSP that’s how we will build them as well. The widget I’m going to be walking you through today is a very simple one that will display the project title and description and make use of the Project class provided by Adobe. It doesn’t have any pretty front end or fancy logic, but it’ll still show you the basics of how to interact with your project. Let’s see the code now.

<%@ page import="com.adobe.cq.projects.api.Project,

                com.adobe.cq.projects.api.ProjectLink,

                org.apache.sling.api.resource.Resource,

                org.apache.sling.api.resource.ValueMap" %>

<%@page session="false"%>

<%@include file="/libs/granite/ui/global.jsp"%>

<ui:includeClientLib categories="cq.projects.admin" />

<%

    //1

    ProjectLink projectLink = resource.adaptTo(ProjectLink.class);

    Project project = projectLink.getProject();

    //2

    Resource projectResource = project.adaptTo(Resource.class);

    Resource projectContentResource = projectResource.getChild("jcr:content");

    //3

    ValueMap valueMap = projectContentResource.adaptTo(ValueMap.class);

    //4

    String active = valueMap.get("active", "false");

    //5

    String title = project.getTitle();

    String description = project.getDescription();

%>

<article class="card-pod cq-projects-Pod foundation-collection-item">

    <i class="select"></i>

    <div class="card">

        <nav class="endor-ActionBar">

            <div class="endor-ActionBar-left">

                <div class="endor-ActionBar-item">

                    <div class="endor-ActionBar-item coral-Button coral-Button--secondary coral-Button--quiet cq-projects-Pod-title"> <%=title%> </div>

                </div>

            </div>

        </nav>

        <div class="cq-projects-Pod-content">

            <div>

                Description = <%=description%>

                </br>

                Project Active? = <%=active%>

            </div>

        </div>

</article>

 page imports.png

Alright there is a lot to talk about here so we’ll start from the top and work our way down. Top of the JSP file we see page imports. These are classes we are going to use in the Java section of the page. Also you’ll see we are pointing to the default global.jsp included with AEM. Finally, you’ll spot that we’ve included a clientlib provided by Adobe. I’ve found this clientlib to contain a lot of the CSS classes necessary to get our widget to look like the rest that Adobe has created.

projectlink.pngAh ha! Now we are to the good part of the JSP, our Java scriptlet. Now I’m going to assume since you are reading an AEM Blog that you have had some amount of experience with the infamous scriptlet, however if you haven’t, here's a helpful tutorial. It’s worth considering that there are a number of ways to avoid having to write your Java code in scriptlet form and this author would recommend them for some more complex widgets, however in our case it’s not necessary for such a simple widget. Back to the code now shall we?

You can see below comment 1 we take our current resource provided by the JSP and adapt it to the Adobe provided ProjectLink class. If you glance down to comment 5 you can see some of the API calls in use. You can find the API on ProjectLink class here . It provides a number of API calls to access common and useful information about the project. I always recommend using the API if possible, it makes the code more readable and is much prettier than a ValueMap. Also I’d be a bad teacher if I didn’t provide you with a link to the other Project related classes that Adobe so graciously provides us. These can be very useful depending on your use case so take a moment to check them out.

Now I know what you’re thinking, “Okay but what if the data I need isn’t available via any of these API calls?”. No problem at all, we can still interact with resources just like you would for any Java backed component. Take a look at the code below comment 2. What we are doing here is taking the Project and adapting it to the resource class. This will directly equate to the resource at /content/projects/{dateProjectCreated}/{projectTitle}. Next we use the getChild() method via resource to locate the content node directly below it. Any dialog options you’ve customized or added in will likely be on this node unless you’ve configured them otherwise.

Take a look at lines 3 and 4 now. On line 3 we take our newly found content resource and adapt it to a ValueMap class. For those who haven’t used them before, ValueMaps are a class made for easily extracting properties from an adapted resource. You can see just how easy it is to extract the property by glancing down to comment 4 where we are able to extract the status of the project currently. valuemaps.png

Now finally it’s time to display all of your hard work. The HTML I’ve used is slightly modified HTML from the out of the box widgets that Adobe provides. I do this so that our widget can blend in with the rest of the Adobe provided widgets. This is also where the clientlib include we used at the top comes into play as many of these CSS classes are defined there. All that’s left now is to include it in your custom project. Browse over to your custom project you created from our first post and include it in the context.xml file at “/apps/myproject/templates/customProjects/customProject/“ inside the “gadget” section of the XML.
custom project.png

There we have it! All done. Of course you’ll probably want to style yours a little nicer but as we can see everything is working as expect for our simple widget. Happy coding!

Topics: Adobe Experience Manager, Developer Think Tank, 3|SHARE Insider

Adam Berberich

Adam is a Certified Adobe CQ Developer/Java Developer and Senior Developer at 3|SHARE.