ng-class: Demystifying AngularJS and Service Portal

featured

ng-class: Demystifying AngularJS and Service Portal

This series of blog shorts is intended for those who have little to no experience with AngularJS. We will take little bites into the world of Service Portal and AngularJS, demystifying it piece by piece.

In this post, we’ll learn how to dynamically add a class name to an html template by using the AngularJS ng-class directive. While there are many ways to utilize ng-class, we’ll focus on a few that will likely be of use to you. To illustrate these methods, let’s build a widget from scratch. The first thing we’ll add is the HTML template for the bootstrap jumbotron component. Let’s include variables for a simple welcome message:

<div class="jumbotron">
   <h1>{{c.data.msg}}, {{c.data.name}}</h1>
</div>

Populate these variables in the controller:

function($rootScope) {
   var c = this;
   c.data.name = $rootScope.user.name;
   c.data.msg = 'Welcome';
}

Don’t forget to inject $rootScope into the controller function. This is what gives us access to current user’s information, like their name.

Save what you have so far. Put the widget on a new page, and check it out:

Now, let’s color the background of the banner. First, we’ll define CSS for two classes:

.morning {
   background: #FC5C7D;  /* fallback for old browsers */
   background: -webkit-linear-gradient(to top, #6A82FB, #FC5C7D);  /* Chrome 10-25, Safari 5.1-6 */
   background: linear-gradient(to top, #6A82FB, #FC5C7D); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
   color: #2B2B2B;
}
.evening {
   background: #1a2a6c;  /* fallback for old browsers */
   background: -webkit-linear-gradient(to top, #fdbb2d, #b21f1f, #1a2a6c);  /* Chrome 10-25, Safari 5.1-6 */
   background: linear-gradient(to top, #fdbb2d, #b21f1f, #1a2a6c); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
   color: #FFFFFE;
}

The Simplest Method

We won’t hardcode a class name into the HTML. We’ll use ng-class to hold a variable that can be any class we want:

<div class="jumbotron" ng-class="c.bannerClass">

In the client controller, we define c.bannerClass.

c.bannerClass = ‘morning’;

As a result, the class morning is included in our template. Look at what we have so far:

Considering Conditions

To conditionally apply morning or evening, we need to first script the necessary logic. In the server script we’ll figure out if it’s before noon, or after noon:

var now = gs.nowDateTime();
var nowTime = now.split(' ')[1].split(':')[0];
if(nowTime > 11) {
   data.itIsEvening = true;
}

Though unrelated to CSS, let’s update the client controller to change c.data.msg depending on the time of day:

c.data.msg = 'Good morning';
if(c.data.itIsEvening) {
   c.data.msg = 'Good evening';
}

Now we’re ready to be dynamic! In the HTML, we’ll apply the morning class by default in the regular class attribute. In the ng-class attribute we’ll use an object to conditionally include the evening class if it is evening:

<div class=”jumbotron morning” ng-class=” { ‘evening’: c.data.itIsEvening } ”>

Due to the cascading nature of CSS, the properties of the evening class will override the properties of the morning class, because evening is defined after morning in the CSS.

If you want to test that this is working, just change your definition of evening in the server script. Rather than 11, use an hour that is earlier than the current hour in your timezone.

I can now see that when evening comes, my widget changes appropriately:

If you don’t want to include morning by default, then you can add another property to the object we created in the ng-class attribute:

<div class=”jumbotron” ng-class=” { ‘evening’: c.data.itIsEvening, ‘morning’: !c.data.itIsEvening } ”>

The above method is great in situations where you could potentially apply more than one class. However, if it is an either morning or evening situation, like what we’re doing, then use a ternary operator to decide which class to use:

<div class=”jumbotron” ng-class=”c.data.itIsEvening ? ‘evening’ : ‘morning’”>

Using a Function

What if it’s more complicated than this? What if, rather than just morning and evening, you want to also include afternoon and night? First, update your ng-class attribute to call a function. This function doesn’t exist yet, so call it whatever you want, like:

ng-class=”c.getTimeClass()”

Then, update your server script to provide an hour value, rather than a simple boolean. It’s pretty simple, just move the nowTime variable from a local var to an item in the data object. Your whole server script will now look like this:

var now = gs.nowDateTime();
data.nowTime = now.split(' ')[1].split(':')[0];

Now, you can use c.data.nowTime on the client side. In the controller, create the getTimeClass function that will return the proper class name to the HTML. Go ahead and update your messaging while you’re at it.

c.getTimeClass = function() {
   var timeClass = 'morning';
   if(c.data.nowTime > 11){
      timeClass = 'afternoon';
   }
   if(c.data.nowTime > 17) {
      timeClass = 'evening';
   }
   if(c.data.nowTime > 21) {
      timeClass = 'night';
   }
   c.data.msg = 'Good ' + timeClass;
   if(c.data.nowTime < 6) {
      c.data.msg = 'Go to bed you maniac';
      timeClass = 'go-to-bed';
   }
   return timeClass;
}

Don’t forget to go add CSS for these new classes. You can use the ones I picked below, or use https://uigradients.com to create your own cool gradients.

.afternoon {
   background: #36D1DC;  /* fallback for old browsers */
   background: -webkit-linear-gradient(to bottom, #5B86E5, #36D1DC);  /* Chrome 10-25, Safari 5.1-6 */
   background: linear-gradient(to bottom, #5B86E5, #36D1DC); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
   color: #fff;
}
.night {
   background: #141E30;  /* fallback for old browsers */
   background: -webkit-linear-gradient(to bottom, #243B55, #141E30);  /* Chrome 10-25, Safari 5.1-6 */
   background: linear-gradient(to bottom, #243B55, #141E30); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
   color: #ccc;
}
.go-to-bed {
   background: #000000;  /* fallback for old browsers */
   background: -webkit-linear-gradient(to bottom, #434343, #000000);  /* Chrome 10-25, Safari 5.1-6 */
   background: linear-gradient(to bottom, #434343, #000000); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}

The best way to test this is to override c.data.nowTime in the controller. So before the getTimeClass function, set c.data.nowTime to different values. Just remember to remove this when you’re done testing.

In Review

We used these ng-class methods to conditionally apply a class in our HTML:

The simplest way to define a conditional class:

ng-class="c.bannerClass"

Apply a class based on object notation and simple expression:

ng-class=” { ‘evening’: c.data.itIsEvening } ”

Apply more than one class conditionally via object notation, by including another object property:

ng-class=” { ‘evening’: c.data.itIsEvening, ‘morning’: !c.data.itIsEvening } ”

Using a ternary operator for deciding between two classes:

ng-class=”c.data.itIsEvening ? ‘evening’ : ‘morning’”

Calling a function to return a class based on more elaborate evaluations:

ng-class=”c.getTimeClass()”

Now you have what it takes to use ng-class in a variety of ways, and make your HTML styles more dynamic than ever!

Aloha,

Jeff