April 25, 2020
Estimated Post Reading Time ~

Angular + Sightly in your AEM Project


In this post, I’m going to talk about the integration of Angular JS and Sightly in AEM projects. Putting these technologies together allows modularization and to improve the performance of your application, making it easier for the developer to work.

Angular JS allows you to create modules in the fronted where you can find the logic already implemented in the controllers, showing it in single pages or partial views.
In this case, I’m going to show you how to use AngularJS ng-templates in order to inject different views or portions of HTML into a script that has the request to the server made with Sightly.

PRE-REQUISITES
Create your initial Maven Project with the basic archetype. If you haven’t set up Maven yet or don’t know how to create an archetype, follow the steps under the “Setup Maven” section of this guide: https://helpx.adobe.com/experience-manager/using/creating-sightly-component.html

In order to explain this integration, I’m going to create an example where we can allow the user to click a link and show information about two fruits. When we click it the app injects some HTML using ng-templates, the HTML which is injected gets the values from the server through Sightly.
Also, we are going to create a simple input with another link that has another template in order to show you the Two-way Data Binding functionality that Angular has.

Back-end
Our Back-end has two important files one that creates the POJO of a fruit, which has two attributes; the name of the fruit and a link of the fruit page with name FriutBean.java

The other file will contain the hardcode values for the fruits and the method which is going to be consumed by the frontend, with the name FruitService.java.

Notice that the class FruitService extends of WCMUse allowing Sightly to use this class. Another thing to take into account is that the method called by the frontend returns a List.
Here’s an example of the structure generated for the backend:


Front-end
Now we can export the code that is in our local machine to AEM, and open the structure with CRXDE Lite or Brackets.

The first thing to do is creating the basic folder structure for your app,
Create your template in: /apps/yourApp/templates/


– next

– next
– next
– OK
Create your component in: /apps/yourApp/components/page/ with the properties of the image:


– next to the end and OK.

Include AngularJS
So far so good we had created the basic structure, now it is time to include AngularJS in our application.
Create a folder with primaryType = “cq:ClientLibraryFolder” in: /apps/yourApp/components/angularComponents/ with name clientlibs and this two properties

(name:categories,
Type:String[],
value:cq.widget)

and

(name: dependencies,
 Type: String[],
 value: angularjs)

Notice that the angularJS dependency refers to the libraries positioned in :
/etc/clientlibs/angularjs/js

In order to get Angular functional, we have to create the app.js. This will be the first file in which Angular searches to initialize their modules, templates, controllers, etc.
Go to /apps/yourApp/components/angularComponents/clientlibs/js/ and create the file. app.js 

(function() {
 'use strict';
 angular.module('app', ['ngRoute'])
  .config(function($routeProvider) {
   $routeProvider.when('/view1', {
     controller: 'Controller1',
     templateUrl: '/view1.tpl' // The ng-template id
    })

    .when('/view2', {
     templateUrl: '/view2.tpl',
    })
  });
})();

Here, we are telling Angular that when the user sets in the url “/view2”, we have a module called “app” in which the templateUrl is going to be injected into the < div ng-view > < /div >

tag. This is routing in angular. On the other hand, we call the Controller1 with view1.tpl when the user sets in the url ‘/view1’.

Now it is time to create the ‘Controller1’, where we can resolve some of the logic, but for this exercise, we are only going to initialize some scope variables and an alert that can tell us the values of the variables.
Go to: /apps/yourApp/components/angularComponents/clientlibs/js/ and create the file controller.js

function Controller1($scope){
//initialize variables of the scope
$scope.firstname = "empty";
$scope.lastname = "empty";
    //eject ng-click 
    $scope.loadView2 = function() {
        alert('The values of the scope of the template: '+$scope.firstname+' , '+$scope.lastname+'');
    }
}
Here we can see how to inject dependencies like the variable $scope which is passed as a parameter to the function of the controller, $scope is one of the most important variables that we have, also it’s the responsibility of sharing values between the view and the controller. You can get more information about this variable in https://docs.angularjs.org/guide/scope

Great we are almost finished, now it’s time to create the view, with the script templates. In order to do it, we have to delete the already generated .jsp file of the component, so:
Go to : /apps/yourApp/components/angularComponents/ and delete the angularComponents.jsp file and create the successor called angularComponents.html. So we can include Angular on it.

angularComponents.html
< div ng-app="app">
    < script type="text/ng-template" id="/view1.tpl">
        < p> First name: < input type="text" ng-model="firstname"/>
Last name: < input type="text" ng-model="lastname"/>
< button ng-click="loadView2()">Show values in Controller 
< /p >
< p >First name:< p ng-bind="firstname" >< /p >
< p >Last name:< p ng-bind="lastname" >< /p >
    
    </script>
    < script type="text/ng-template" id="/view2.tpl" data-sly-include="template.html">

    < /script >

    < div>
        < p>Enter a value: < input type="text" ng-model="name">
        < p ng-bind="name">< /p>
        < ul class="menu">
            < li>< a href="#/view1">Scope example
            < li>< a href="#/view2">Show the list of cars
        < /ul>
        <div ng-view></div>
        <!--Include angular js -->
            <sly data-sly-use.clientLib="/libs/granite/sightly/templates/clientlib.html" data-sly-call="${clientLib.js @ categories='cq.widgets'}" data-sly-unwrap />
        </div>
    </div>
</div>

Take into account the next tips:
sly data-sly-use.clientLib: Declare the variable clientLib loaded with the …/clientlib.html template, so that you can use it later.
sly data-sly-call: this is the way Sightly includes the clientLibs files of your component. In this case, we are including all the .js files with a clientLibs folder which has the property categories equals ‘cq.widget’.
data-sly-include: includes useful templates like init.jsp and template.html
ng-app: Declares the app scope module created in the app.js file.
ng-model: is a directive that binds an input, etc to a property in the scope using NgModelController, which is created and exposed by this directive.
ng-bind: Replace the content of the specified HTML element with the value of a given expression, and updates the content when the value of that expression changes. Here we are showing the value of the ng-model.
ng-view: It is a directive that complements the $route service by including the rendered template of the current route into the main layout ( angularComponent.html ) file. Here is where the templates are going to be rendered.
ng-click: Allows to have a function in the controller which is going to be called when the user clicks on the element with this tag.
ng-template: Indicates the content to be rendered inside the ng-views.

Problem:
If you want to include the call to the server with Sightly inside an ng-template, you are going to crush the app and probably the render will fail.
Eg: To begin with this exercise go to your angularComponents.html and select the script with id = “view2.tpl” is. Change the data-sly-include=”template.html” for data-sly-use.fruitService=”com.mycompany.testAngular.models.FruitService” (which is the call to the server) and insert this code inside the script’s tags: 

< div data-sly-list.fruit="${fruitService.myfruitList}" > 
    Slightly fruit
< ul > 
       < li > name: ${fruit.name}< /li >
       < li > link: ${fruit.link}< /li >
< /ul >
< /div>
result:

As you can see no information was displayed.

Solution for Integrating Angular with Sightly
Create a new file called template.html in:/apps/yourApp/components/angularComponents which has the call from Sightly to the server like this:

template.html
< div data-sly-use.fruitService="com.mycompany.testAngular.models.FruitService" >
    < div data-sly-list.fruit="${fruitService.myfruitList}" > 
        Slightly fruit
        < ul > 
            < li > name: ${fruit.name}< /li >
            < li > link: ${fruit.link}< /li >
        < /ul >
    < /div >
< /div > 

And then include this file in the angularComponents.html like did before. 
< script type="text/ng-template" id="/view2.tpl" data-sly-include="template.html">

This loads the content of the < script > into the $templateCache service so that ng-view (and other directives) can use it. You also need to assign an id to it, through which it can be referenced in other places. In this case, we’ll use this id in app.js while configuring modules.

You should note that the extension “.tpl” in the id is optional. You can leave it without extension or assign the one you want. All you need to do is specify a name to which you can later refer.

If your template is not that large, you might benefit from declaring it inside ng-template. In a real-world app, you won’t probably ever need this. It is a better practice to create different HTML files for different templates as it keeps your app maintainable in the long run and does not clutter your main view with < script > tags.

The last thing this component needs is a Dialog, so go to: /apps/yourApp/components/angularComponents/and create a dialog following these steps: Right-click on the component node-> create Dialog -> label = dialog, title = dialog – > OK. Now we will see our component on the SideKick.
Now we need the basic structure to include the component in a parsys so we can drag in and drop the component from the sidekick.

So go to : /apps/tourApp/components/page and create a new component like this :

-next
-next
-next
-OK

Here it is the final structure:

The last step creates a page in AEM WCM with the template we created at the beginning.

Remember that once you go to the browser and navigate to your just created app you need to change it to Display view and edit the parsys, select your just created angularComponent, select edit view, and drag the component and drop it inside the dragging section in the parsys.
Change to display view :
Here are some result screenshots
Click on Scope example


Click on Show the list of fruits



References:
https://www.sitepoint.com/premium/books/angularjs-novice-to-ninja/preview/using-ng-template-780c812
https://docs.angularjs.org


By aem4beginner

No comments:

Post a Comment

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