Part 1 - Angular 2 with AEM – Introduction, Challenges, Installation and Prerequisite


I am writing about AEM after long time and there is reason for that :-) I was learning something else interesting and that interesting thing is frontend technologies. So far in my professional career I have spent most of my time in designing and developing server side applications mainly using Java technology stack (Spring, ORM, JMS and what not) with basic UI development using JSP/JSF, HTML, Velocity, Sightly, jQuery, ExtJS etc. Also, in last few years I have delivered many applications which is combination of AEM, other CMS and Java backend but, I felt that still there is something missing and that missing piece is end to end knowledge of frontend development. So that’s what I was focusing on frontend development in recent past. I thought it is good time to combine frontend development knowledge with AEM and come up with something interesting that might help my friends out there.

In this multi series post (and tutorial in coming parts of this series), I’ll show you how you can use Angular 2 in AEM. There are lot of post already out there then, why do I need a separate post on this topic? I see a lot of articles on web that are trying to address how to use AEM and Angular2 together but, most of them are either incomplete or just shows how to create clientlib for Angular2 dependencies or how to create a plain vanilla Angular 2 component (not AEM component) that authors cannot drag and drop (like regular AEM components). For almost last 2 years I spent a good amount of time learning front end technologies like (Angular 1.x, Angular2, ES6, Typescript, Ionic 1 & 2, Native Script etc.) along with Node.js and I felt this is the time when I know both worlds; AEM and Angular 2 quite well and I can attempt to develop something using AEM and Angular 2 by harnessing power of both. You’ll have to be focused and patient while going through this multi series post.
For those who don’t know what is AEM and Angular 2, I’ll being with quick non-technical introduction.
What is AEM?
Adobe Experience Manager (AEM), is a comprehensive content management platform solution for building websites, mobile apps and forms - making it easy to manage your marketing content and assets. AEM empowers business users and non-technical staff to create and manage content as per business needs.
What is Angular 2?
Angular is a platform that makes it easy to build applications with the web. Angular combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular 2 comes with almost everything you need to build a complicated frontend web or mobile apps, from powerful templates to fast rendering, data management, HTTP services, form handling, and so much more. Angular 2 is a component centric framework that promotes reusable component development. In Angular 2, “everything is a component.” Components are the main way we build and specify elements and logic on the page, through both custom elements and attributes that add functionality to our existing components.

Since Angular2 is primarily based on Typescript therefore we get all the benefits of a typed language. Angular 2 and TypeScript are bringing true object oriented web development to the mainstream, in a syntax that is strikingly close to Java 8.
Why use Angular 2 in AEM?
For any delivery channel (web, mobile etc.) content is no doubt key but, at the same time it is also very important how that content is presented to users (this is where user experience comes). No matter how good content is, if it is not available to users in the format that is easy to read, understand, in right context with good performance then it will lose its value. This is where Angular 2 helps to design more robust and performant user experience using modern technology and standards.

Challenges that I faced while integrating Angular 2 with AEM
  1. AEM and Angular 2 components are different: Angular 2 is modular in nature, what that means is there are number of smaller modules that you can choose to mix and match based on what is required in your project. When you are developing Angular 2 application outside of AEM this is not a big challenge in terms of building and shipping an Angular 2 application out of the door because there are many build tools (e.g. Angular 2 CLI) are available to take care of managing these smallers angular modules and dependencies. But, when we are in AEM, components are just building blocks and content authors can drag-drop these components anywhere and as many times as they need so, reusability is key i.e. authors should be able to use Angular 2 components in same way as regular AEM component. So this mean build tools that are available today for Angular 2 application can’t help because those tools need to know upfront where components have been used and then these tools compiles applications but, in AEM this is different (as we discussed above).

To address this problem we need to write our custom build script using gulp (we can use grunt as well) and Maven.

  1. Angular 2 application root component bootstrapping and AEM component model: typically an Angular 2 application has one root element where main application is bootstrapped. All other Angular 2 components have to be child of this root element else Angular will not detect them. For example:

In above diagram is application root component and everything else (including components imported from other Angular 2 modules) needs to be rendered inside . This is big challenge because we want parsys to be available inside an Angular 2 component, and we should also be able to drag-drop component in that parsys...this sounds complex huhhhh!!!  Yes, it is little complicated and took some time for me as well to figure out how this can be achieved.

To overcome this, we need to use some internal Angular 2’s core classes like “ComponentFactoryResolver” and “ApplicationRef” to change the way Angular 2 application is bootstrapped in normal applications and loading Angular 2 components dynamically at runtime.

  1. Angular 2 component & authoring: one of the key capability of AEM component is content authors have full control over text/labels, they can change text without IT team’s involvement but, on the other hand Angular 2 component need to know the text values (labels etc.) upfront and if there are any changes then we need to rebuild application or at the very best we can externalized labels into translation bundle files so that we don’t need to change code but, still this is not aligned with how component authoring works in AEM.
To overcome this, we need to use Angular 2 features like @Input so that we can read JCR properties and pass it to Angular 2 component’s template for rendering.

  1. Angular 2 component’s view/template: Let’s look at a simple Angular 2 component

import {Component, OnInit} from "@angular/core";

@Component({
   selector: "app",
   templateUrl: "/apps/ngaem/content/ng-app/app.html"
})
export class AppComponent implements OnInit {
   ngOnInit() {
       console.log("Application component initialized ...");
   }
}

As you can see, Angular 2 component’s actual view is in some external template “app.html”. If we want to treat an Angular 2 component as AEM component then app.html in this case will become sightly template (or JSP, JSP is not recommended to use because we want to leverage HTML5 features when using Angular 2). If you notice, the template is directly fetched from /apps folder (which is a secured folder on server) and we don’t want users to have direct access to anything that resides in /apps folder in publish environment.

To overcome this, we need to write a custom Sling servlet that can serve view/template to angular component. This servlet will be responsible for reading view file (e.g. app.html) from apps folder and send text/html response back to caller (in this case Angular 2 component). Here is a quick example how view will be referenced from Angular 2 component:

@Component({
   selector: "app",
   templateUrl: "/bin/ngtemplate?path=/apps/ngaem/content/ng-app/app.html"
})

/bin/ngtemplate is Sling servlet that serves the content of app.html

  1. Preview of Angular 2 component in author environment: a component can be dropped by an author on a page (when they are in edit mode) and they can preview how actual pages looks like (in preview mode). When an Angular 2 component is dropped on a page it needs to be intercepted by Angular 2 library and bootstrap or attach it to DOM. Even though the Angular 2 library is available on page but, for some weird reason Angular was not able to bootstrap/attach component’s view when I was in EDIT and PREVIEW mode. For Angular component to work I have to use wcmmode=disabled in query string.

Image: Angular 2 TextArea Component in EDIT/PREVIEW mode

Image: Angular 2 TextAreaComponent in DISABLED mode

To overcome this I used “wcmmode”, and if wcmmode is either EDIT or PREVIEW directly render the .html file of component and in this case data will not be binded i.e. {{some_angular_variable}} will be rendered rather than actual value. Here is a quick code snipped that show how I am loading template in EDIT/PREVIEW mode v/s when wcmmode is DISABLED (need to pass query parameter in URL ?wcmmode=disabled):

<div data-sly-use.logic="logic.js">
   <div data-sly-test="${wcmmode.edit || wcmmode.preview}">
<!-- Render HTML file in EDIT and PREVIEW mode-->
    <section data-sly-include="text.html"></section>
   </div>
   <div data-sly-test="${!wcmmode.edit && !wcmmode.preview}">
<!-- Render by Angular 2 component in wcmmode=DISABLED mode-->
    <text-area text="${properties.text}"></text-area>
   </div>
</div>

  1. Speed of development and validating Angular functionality and AEM functionality independently: developer are more productive when they can make code changes and quickly verify it without redeployment. We feel more confident when we have suite if unit tests to verify our code so that undesirable code changes can be caught during development. When we want to use Angular 2 in AEM we have to deal with 2 different approaches for developing and testing application because Angular 2 development itself is quite different than AEM and Angular 2 is mostly used without AEM. Challenge come when we want to use both together. Both Angular 2 and AEM components should be unit testable (Angular 2 testing using Mocha, Chai, Sinon etc.) AEM with Junit, Mockito etc. and developer should be able to test their code quickly without redeployment.
To do this, I have leveraged power of frontend build tools Gulp to create two separate Angular 2 build tasks:
  1. One for AEM which compiles Typescript files, updates template path in Angular 2 component with Sling servlet context path, copy resources that are needed for creating AEM CRX package
  2. Second task for building pure Angular 2 project that can be built and tested outside of AEM using a local lite-server https://github.com/johnpapa/lite-server

  1. Importing Angular 2 dependencies and loading them on AEM template: Angular 2 primarily recommends to use Typescript for Angular 2 application development although you can use Javascript as well. If you are from Java background you’ll feel like you are write Java code when you use Typescript and you get all most all the benefit of a typed language. When you want to use Angular 2 in AEM you need to bring in all dependencies of Angular (e.g. @angular/core, @angular/common, @angular/compiler, @angular/http etc.) in AEM and make them available on your pages via template. These dependencies are modular and can be loaded on demand (i.e. when it is really needed by your Angular 2 component, services/providers). For example, you are writing a simple Angular 2 Text component that does not talks to any REST service then you really don’t need @angular/http module loaded on your page. In AEM there are 2 ways you can achieve this one using clientlib (define inter-dependencies between various modules) or you can use frontend bundle packaging and loading tools like Webpack or Systemjs.

In this series of tutorial, I am going to use Systemjs. Systemjs allows you load JS dependencies from AEM.

I just wanted to give you an overview of some of challenges that I faced while integrating Angular 2 with AEM so that you can follow rest of parts in this series with a better context and background. I’ll cover each of these challenges in more other parts of this series so that you can get more knowledge about these topics.

What you need to know to follow remaining parts of this series?
If you know Java, AEM and Angular2 you can easily follow this series of tutorial but, if you want to do some hands on along with going through this tutorial then I’ll recommend you to get fair understanding of following:
  1. Good understanding of Java and AEM (components, templates, Sling Servlet etc.)
  2. Good understanding of JavaScript and Typescript (https://www.typescriptlang.org)
  3. Good understanding of Angular2 (https://angular.io/docs)
  4. Good understanding of Systemjs (https://github.com/systemjs/systemjs)
  5. Basic understanding of frontend build tool (gulp: http://gulpjs.com) and Maven build tool (https://maven.apache.org)

Tools and Installation
Also, to build and run project you’ll need to install:
  1. TypeScript - https://www.npmjs.com/package/typescript
  2. Java /JDK 1.7 or later - https://www.java.com/en/download
  3. AEM - If you don’t have AEM already then getting it might be tricky because it is licensed. You can look at this thread https://forums.adobe.com/thread/2322257 and another link https://helpx.adobe.com/support.html#/top_products

I hope you have got some context now and will enjoy next parts in this series. Be ready with installation of tools that I have listed above. Stay tuned for a github repository with sample code and links for next parts in this series.

Part 2: http://suryakand-shinde.blogspot.com/2017/06/part-2-aem-with-angular-2-building.html

Github Project/Source Code: https://github.com/suryakand/aem-angular2

Thanks for reading!

Comments

Bala Sundar said…
Hi SuryaKand,

i am using the similar kind of approach and bundling the js and uploading to dam. i am facing strange issues of [routerLink] , ngIf
template issues. These directives are not resolving. its woring fine on non-WEM servers. any suggesgtions on it.


Thanks,
Bala

Popular posts from this blog

Sling Authentication

CQ Development - OSGi bundles and Components

Multiple log files using log4j appender

Create an AEM (CQ) project using Maven