Simple AngularJS directive

So I found many articles on using AngularJS directives, which go into great detail for very complex directives. I couldn’t find any on just a relatively simple directive, so I thought I’d write about it.

First of all, an AngularJS directive defines a reusable HTML tag that you can use in your HTML files. It’s very useful if you want to create some complicated custom tags, or even just simple ones, that you can reuse everywhere.

In my case, I just wanted to give my users a message for them to add the system email to their spam filter allow list, so no system-generated emails get blocked. I wanted to do this everywhere an operation included a system-generated email to the user. I wanted to style the message in a particular way, translate it according to the user’s preferences, and I didn’t want to copy/paste it in those several places. I thought it would be difficult in case I wanted to change the styling, wording, or so on, I’d have to do it in many places. This is where an AngularJS directive becomes useful. I can define the directive in one place, and use it in many places.

This is how the directive is defined in JavaScript:

.directive('emailSpamMessage', function() {
  return {
    template: '

<span class="label label-danger">{{"NOTE" | translate | uppercase}}</span> {{"SPAM_MESSAGE" | translate {HOSTING_NAME:CONSTANTS.HOSTING_NAME,SYSTEM_EMAIL:CONSTANTS.SYSTEM_EMAIL} }}' 
  } 
})

And this is how it would look in HTML:

<email-spam-message></email-spam-message>

And that’s it! Note that the directive in JavaScript is defined as emailSpamMessage, but in HTML as “email-spam-message”. AngularJS does the conversion for you.

Also note that in the controller associated to the HTML that the custom directive is in, needs to have the correct includes for it to work fully. For my particular example the controller will need to have $translate (angular-translate) and a CONSTANTS variable included.

Limiting upload of number of files in ng-file-upload

ng-file-upload is a wonderful module to help you manage uploading files through AngularJS. Head on over to https://github.com/danialfarid/ng-file-upload to check it out.

One thing that isn’t obvious is how to limit the number of files that a user can upload. (This of course only applies if you are allowing multiple file uploads).

One way to limit the number of files a user can upload is through the “ngf-validate-fn” angular directive. This directive can be used to call a custom function defined in your controller that validates the file.

In this custom validation function, you can check the number of files that already exist in the files model, and return true (meaning validation passed, file should be allowed) or false (or an error name, meaning validation failed… the max number of files has reached).

Let’s say you want to limit the maximum number of files uploaded to 10. It would look like this in your html:

<div ngf-select ngf-multiple="true" ng-model="files" ngf-validate-fn="validateFile($file)" />

And in your controller:

$scope.validateFile = function(file)
{
  if($scope.files.length>=10)
    return "TOO_MANY_FILES";
  return true;
}

And that’ll do it.

HOWEVER, big caveat: This will only work if the user selects one file at a time. If the user selects multiple files all at once (from the file-selection dialog box their browser presents), then this limitation trick will not work, and more files will get through. I am currently in the process of either myself implementing this feature as a native directive in the ng-file-upload module, or waiting till someone else implements it. I’ve posted this as an enhancement request on the module’s github page.

MEAN stack: associating a socket with a user

I’m using the MEAN stack for an application I’m working on. The project was seeded using the Angular fullstack yeoman generator (https://github.com/DaftMonk/generator-angular-fullstack/).

Out of the box the project has support for websockets (using socket.io), and users (using passportjs). However, sockets on the server side in express running on node are not tied to users, out of the box.

For several reasons the application likely needs to know what user a socket belongs to. For example, if there’s a change made to a model that needs to be emitted, you may need to emit it to only users with a certain role.

To get around this, I made a bunch of modifications which I’ll detail below. Essentially, the user object will get saved within the socket object. So when a socket is being processed, say through a model level trigger (i.e. “save” or “delete”) using mongoose for example, the user object will be in the socket and can be used in whatever processing logic.

The MEAN project seeded from the angular fullstack generator uses a token generated through jwt, which is stored in a cookie, to authenticate a user. So when a user login occurs, an event can be emitted with the jwt token over the socket to register the user with the socket. Furthermore, in your socketio.on(‘connection’,…) function in express, you can read the cookie to get the jwt token, then get the user and put it in the socket. This is essential so that if a user is already logged in, and returns to your web application (or opens a new tab to your application) and a new websocket is created, the cookie can be used to associate the socket with the user, since a new login event will not be emitted at that point.

First, let’s define a function that can take a token either directly as a parameter, or read it from the cookie in a socket, and get the user. This same function can be called from a login emit event with a jwt token as the payload over the socket, or from socketio.on(‘connection’,…).

var auth = require('../auth/auth.service');
function setupUserInSocket(socket, inputToken)
{
  var tokenToCheck = inputToken;
  if(!tokenToCheck && socket && socket.handshake && socket.handshake.headers && socket.handshake.headers.cookie)
  {
    socket.handshake.headers.cookie.split(';').forEach(function(x) {
      var arr = x.split('=');
      if(arr[0] && arr[0].trim()=='token') {
        tokenToCheck = arr[1];
      }
    });
  }
  if(tokenToCheck)
  {
    auth.getUserFromToken(tokenToCheck, function (err, user) {
      if(user) {
        console.info('[%s] socket belongs to %s (%s)', socket.address, user.email, user._id);
        socket.user = user;
      }
    });
  }
}

Note that the cookie is in socket.handshake.headers.cookie. Also note that I call auth.getUserFromToken, which is another function I created that decrypts the user ID from the jwt token, queries the user from the model, and returns it. The function looks like this:

var User = require('../api/user/user.model');
var async = require('async');
var config = require('../config/environment');
function getUserFromToken(token, next)
{
  async.waterfall
  (
    [
      function(callback)
      {
        jwt.verify(token, config.secrets.session, function(err, decoded) {
          callback(err, decoded);
        });
      },
      function(decoded, callback)
      {
        if(!decoded || !decoded._id)
          callback(null, null);
        else {
          User.findById(decoded._id, function (err, user) {
            callback(null, user);
          });
        }
      },
    ],
    function(err, user)
    {
      next(err, user);
    }
  );
}

Next, let’s use socketio.on(‘connection’,…) to call the function with the socket. If the jwt token is already in the cookies, meaning the user already logged in previously, the user will be associated with the socket:

socketio.on('connection', function (socket) {
  setupUserInSocket(socket);
  //...
});

And that’s it for that particular scenario! Next, let’s worry about when a user actually logs in. Within socketio.on(‘connection’, …) we can listen for login emits from the client over the socket like so:

socket.on("login", function(token,next) {
  setupUserInSocket(socket,token);
  next({data: "registered"});
});

And on the client side, we emit the login event over the socket when a successful login occurs. This can be done in a number of ways, but I decided to do it in login.controller.js. After Auth.login() is called, I call socket.login():

angular.module('classActApp')
  .controller('LoginCtrl', function ($scope, Auth, socket, ...) {
    //...
        Auth.login({
          email: $scope.user.email,
          password: $scope.user.password
        })
        .then( function() {
                  //...
                  socket.login();
//...

And in the client side socket.service.js, the login() function does the following:

angular.module('classActApp')
  .factory('socket', function(socketFactory, $location, CONSTANTS, Auth) {
return {
login: function () {
  socket.emit("login", Auth.getToken(), function(data) {
  });
},

Note that you also need to worry about logouts. If the user logs out from your web application, but sticks around on your web application, the socket for that session will remain associated to the user they were logged in as previously. This could be undesirable for several reasons. So in your express side of things (server side), you want to listen for logout events and clear out the user from the socket like so (note, this is added within socketio.on(‘connection’,…)):

socket.on("logout", function(next) {
  if(socket && socket.user) {
    console.info('[%s] socket being disassociated from %s (%s)', socket.address, socket.user.email, socket.user._id);
    socket.user = null;
  }
  next({data: "un-registered"});
});

And in your angular side of things (client side), when the user logs out, you want to emit a logout event over the socket. In the angular fullstack seeded project I’m using, this happens in navbar.controller.js which has the logout function.

angular.module('classActApp')
  .controller('NavbarCtrl', function ($scope, $location, socket, ...) {
    //...
    $scope.logout = function() {
      //...
            socket.logout();

And in socket.service.js:

angular.module('classActApp')
  .factory('socket', function(socketFactory, $location, CONSTANTS, Auth) {
    //...
    return {
      //...
      logout: function () {
        socket.emit("logout", function(data) {
        });
      },

And that’s it! Now all your sockets have the user they belong to (if any) associated to them (accessible from socket.user on the server side). And when emitting events from the server side from the socket, or when reading events emitted from the client side over the socket, we can now know the user the socket belongs to!

Using Grunt to deploy to individual OpenShift Applications

I ran across this problem using the MEAN stack seed project generated through the angular fullstack generator (https://github.com/angular-fullstack/generator-angular-fullstack). The seed project’s developers made it easy to deploy an application to OpenShift, however they set it up so you can only deploy to a single OpenShift application instance.

One of the requirements for my current MEAN project is to deploy it to two environments: a staging environment and a full blown production environment. However with this seed project and respective Grunt buildcontrol directives, that wouldn’t be possible.

So I took it upon myself to edit the Grunt file and the yeoman javascript to deploy to OpenShift, to allow it to create multiple environments.

The first step is to edit generator-angular-fullstack\openshift\index.js file that ships with the yeoman generator for angular fullstack. (Note: this file is outside of your actual MEAN project seeded by the generator, typically in your home directory, so you’ll need to search for it on your filesystem). As writing of this blog post, openshift\index.js has hardcoded the application name to be ‘openshift’. Find all occurences of ‘openshift’ (single quotes included) and replace it with this.deployedName (no single quotes). This will allow the application name to be the actual name you’ll input when running this openshift deployment yeoman script.

Secondly, you’ll need to edit the Gruntfile.js in your project. Skip down to the buildcontrol. Under openshift, change the remote field from ‘openshift’ to grunt.option(‘openshift_target’). grunt.option() allows you to take an argument from the command line, so this way you can specify the application name you want to deploy to.

And voilà, that’s it. Now you have the capability to deploy (and update) your MEAN application to multiple OpenShift application environments.

As per the angular fullstack generator documentation, to deploy to OpenShift, you would run the following command:

yo angular-fullstack:openshift

In the yeoman script run in the command above, you’ll be asked for the application name. I named mine “staging” and “production” (two separate environments created by running the command twice). And then to deploy to your application initially, or deploying all code updates, you’d run the commands.

grunt build
grunt buildcontrol:openshift --openshift_target=staging
grunt buildcontrol:openshift --openshift_target=production

Vaadin: Executing custom JavaScript from a thread, or loading custom JavaScript functions into global scope

As you may know already, in Vaadin you can use com.vaadin.ui.JavaScript.getCurrent().execute(…) function to execute some custom JavaScript on the client browser.

  1. Executing custom JavaScript from a thread:
    The above works well as long as the JavaScript execute() method is being called on the main UI thread. However, if JavaScript.getCurrent().execute() is called from a background thread, the JavaScript won’t get executed until there is a periodic refresh of the UI, or there’s a UI event (triggered by the user, such as a mouse click somewhere). This can seem to cause erratic behavior, with the JavaScript executing at unpredictable times. (Side note: any Vaadin UI access/manipulation from a background thread needs to be done inside com.vaadin.UI.getCurrent().access(new Runnable() { … });, and also note that you want to do your time-consuming heavy lifting first (such as retrieving data from the back end) and then go into UI.getCurrent().access(…) to manipulate the UI).To get around this problem, simply use Vaadin Push. You’ll need to enable push if not already (see Vaadin documentation on how). Then depending on the push mode you’ve used (manual or automatic) you’ll either need to call com.vaadin.ui.UI.getCurrent().push() or not (for manual mode you’ll need to call the push() method, for automatic mode it will be called after the runnable you send to the UI.access(…) method finishes executing). So call get JavaScript.execute(…), and then UI.push() last. Example:

    new Thread() {
        public void run() {
            //some long running background work
                 UI.getCurrent.access(new Runnable() {
                public void run() {
                    JavaScript.getCurrent().execute("alert('Background Task Complete!');");
                                UI.getCurent().push();
                }
            });
        }
    }.start();
  2. Loading custom JavaScript functions into global scope:
    This is extremely useful so you can define a JavaScript function which you can use later from JavaScript.getCurrent().execute(…), such as inside an event (a button click, for example). However, the JavaScript function will need to be in the global scope by injecting it into thetag for the HTML page served by Vaadin. To do this, use the following code while your Vaadin view is being created, or is being enter()’ed.

    StringBuilder script = new StringBuilder(); script .append("var head = document.getElementsByTagName('head')[0];") .append("var script = document.createElement('script');") .append("script.content='function sayHello() { alert(\"Hello!\");}';") .append("head.appendChild(script);"); JavaScript.getCurrent().execute(script.toString());

    Note: as I mentioned, a JavaScript function can only be loaded this way when the view is being created, or in the view’s enter() method. To create a function this way AFTER the page is already loaded (such as through some event), you’ll need to use Vaadin Push, and call UI.getCurrent().push() after the JavaScript.getCurrent().execute() even though you’re not on a background thread.

  3. You can define a function in the script tag being created above, which can then be called later on through JavaScript.getCurrent().execute(“sayHello();”); perhaps inside a Vaadin button click listener.

Enjoy!

AngularJS creating multiple $resource endpoints in a service

So this had me baffled for a bit. For using Angular’s $resource in your Angular service, you map it to a particular URL with (optional) parameters defined for that URL. Then how can you have multiple resources with their own unique URLs mapped in the same service?

For example, here’s a service called User which maps to the URL “/api/users/…”:

angular.module('myApp')
  .factory('User', function($resource) {
    return $resource('/api/users/:id/:controller', {
      id: '@_id'
    }, {
      changePassword: {
        method: 'PUT',
        params: {
          controller: 'password'
        }
      },
      get: {
        method: 'GET',
        params: {
          id: 'me'
        }
      }
    });
  });

As you can see, there’s one resource in this service that maps to the one URL, so then how can I add another URL for the $resource?

The answer turned out to be pretty simple, actually. What you have to do is create an object (JSON) of $resources that are returned for the service. You can have individual elements inside the object that each map to a different $resource. So, for example:

'use strict';

angular.module('myApp')
  .factory('User', function ($resource) {
    return {
      WithId: $resource(
        '/api/users/:id/:controller',
        {
          id: '@_id'
        },
        {
          changePassword: {
            method: 'PUT',
            params: {
              controller: 'password'
            }
          },
        }
      ),
      Misc: $resource(
        '/api/users/misc/:controller',
        null,
        {
          generateResetPasswordToken: {
            method: 'POST',
            params: {
              controller: 'generateResetPasswordToken'
            }
          },
        }
      ),
    };
  });

In the above example, in the “User” service, we have two resources that can be accessed. To access “changePassword”, we can use User.WithId.changePassword (which maps to a particular URL), and to access “generateResetPasswordToken” we use User.Misc.generateResetPasswordToken (which maps to another URL).

Voila!

Correctly doing post-login processing in the DaftMonk AngularJS full-stack seed

So I’ve been working on a personal project using the MEAN stack (MongoDB, ExpressJS, AngularJS and NodeJS)! The nerd in me has been pretty excited to learn something completely new and different. I’ve never done full-stack development strictly in JavaScript, and so far I’m finding it to be pretty neat. I’ll be making posts about things I struggle with, or find useful, as I progress.

Anyway, I used the DaftMonk AngularJS full-stack yeoman generator (https://github.com/DaftMonk/generator-angular-fullstack) for my project seed. I definitely recommend it if you’re starting out fresh with MEAN (or even if you’re not), since it speeds up the initial setup and development immensely.

My problem arose as I was wiring up some post-processing to be done after a user logged in. In the login controller (login.controller.js), after the login function is called from the Auth service, there is a function in “.then()” that is called upon success.

Auth.login({
  email: $scope.user.email,
  password: $scope.user.password
})
.then( function() {
    //login was successful
    //...
  }

However, even though the user has logged in, the user data is not available yet! So, you cannot access the current user’s data properties (such as their role) through Auth.getCurrentUser() (for example the Auth.getCurrentUser().role field will be undefined). This is due to the fact that the data is loaded asynchronously (I’m still trying to get the hang of how that works).

The way around this is to use the Auth.isLoggedInAsync(…callback…) function. The callback sent to isLoggedInAsync is called after the user has finally been loaded, which will guarantee your post-login-processing code being executed after the data for the user is available.

This is how you’d make use of Auth.isLoggedInAsync(…):

Auth.login({
  email: $scope.user.email,
  password: $scope.user.password
})
.then( function() {
    Auth.isLoggedInAsync(function(success) {
      //Auth.getCurrentUser() will now return the user with all the properties fully loaded
    }

Enjoy!