TypeScript and the MEAN Stack: Getting started Part 3

Introduction

Up until now, we set up the main tools necessary to get TypeScript and the MEAN stack up and running. We got a basic server application running against MongoDB. Today we will dive into the client side, getting a basic front-end written up using AngularJS.

Bower

Similar to npm, bower is a package manager that aids in obtaining packages for use on the front-end. Installation can be done via npm:

$ npm install –g bower

We will create two files to have bower working nicely in our project. The file .bowerrc will allow us to specify where the packages go, and bower.json works in a similar way to package.json, but for bower instead of npm:

First, .bowerrc:

{
    "directory": "public/lib"
}

And bower.json:

{
   "name": "MeanType",
   "version": "0.0.1",
   "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, Node.js and TypeScript",
   "dependencies": {
     "bootstrap": "~3",
     "angular": "^1.2"
   }
}

Let’s go ahead and grab angular and bootstrap by running the command:

$ bower install

Now that we have the packages installed, we need to grab the type definition files for angular, bootstrap and jQuery, since angular has a dependency on jQuery. This is the exact same process described in previous posts.

Updates on the server

Updates on User Controller

The controller on the server needs to be updated to return JSON instead of plain text. We also need a method to retrieve all the users:

import express = require("express");
import mongoose = require("mongoose");
import userModel = require("../models/userModel");
 
import IUser = userModel.IUser;
import repository = userModel.repository;
 
export function createUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.create({ name: userName }, (error, user) => {
        if (error) {
            res.send(error);
        } else {
            res.jsonp(user);
        }
    });
}
 
export function retrieveUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.findOne({ name: userName }, (error, user) => {
        if (error) {
            res.send(error);
        } else {
            res.jsonp(user);
        }
    });
}
 
export function retrieveUsers(req: express.Request, res: express.Response) {
    repository.find((error, users) => {
        if (error) {
            res.send(error);
        } else {
            res.jsonp(users);
        }
    });
}

Updates on Routes

Since we updated some logic over on the server, we need to update some routes to get the desired behaviour over to the client:

indexRoutes.ts:

import express = require('express');
 
export function index(req: express.Request, res: express.Response) {
    res.sendfile('./public/views/users.html');
};

Note that the above route is to make sure that we can fire up the application and that we go straight to the users view, which will be detailed later on.

userRoutes.ts:

import express = require("express");
import controller = require("../controllers/userController");
 
/*
 * User Routes
 */
export function list(req: express.Request, res: express.Response) {
    controller.retrieveUsers(req, res);
}
 
export function create(req: express.Request, res: express.Response) {
    controller.createUser(req, res);
};
 
export function read(req: express.Request, res: express.Response) {
    controller.retrieveUser(req, res);
};

Client code

From the client side, we will go ahead and create a page for users and a controller. Angular offers many more things, but again, we are keeping this simple for now, making sure we have basic connectivity and data retrieval out of the way. Later on we will refactor this code and follow established practices.

Let’s go ahead and create the necessary files and folders in the folder public:

image

The Controller

For the sake of brevity, we will create the User class, the controller and relevant interfaces in a single file in userClientController.ts:

/// <reference path="../../Scripts/typings/angular/angular.d.ts"/>
 
module MeanUsers {
 
    export class User {
        name: string;
    }
 
    export interface IUserScope extends ng.IScope {
        vm: UserClientController;
    }
 
    export class UserClientController {
        users: User[];
        newUserName: string;
 
        $http: ng.IHttpService;
 
        static $inject = ['$scope', '$http'];
 
        constructor($scope: IUserScope, $http: ng.IHttpService) {
            $scope.vm = this;
            this.$http = $http;
 
            this.getUsers();
        }
 
        getUsers = () => {
            this.$http.get<User[]>("/users")
            .success((retrievedUsers, status) => {
                this.users = retrievedUsers;
            });
        }
 
        createUser = () => {
            var user = new User();
            user.name = this.newUserName;
            this.$http.post<User>("/users/" + user.name, user)
            .success((createdUser, status) => {
                this.users.push(createdUser); 
            }); 
        }
    }
}

The View

And now a basic view for users.html:

<!DOCTYPE html>
<html data-ng-app ="meanType">
  <head>
     <title>Users</title>
     <script type="text/javascript" src="../lib/angular/angular.js"></script>
     <script type="text/javascript" src="../app.js"></script>
     <script type="text/javascript" src="../controllers/userClientController.js"></script>   </head>
   <body>
     <div data-ng-controller="MeanUsers.UserClientController">
      <form class="form-horizontal" ng-submit="vm.createUser()">
         <input type="text" ng-model="vm.newUserName" size="30"
                placeholder="user name">
         <button class="btn" type="submit" value="add">
                     +
         </button>
       </form>
       <table class="table table-striped table-hover" style="width: 500px;">
         <thead>
           <tr>
             <th>Name</th>
           </tr>
         </thead>
         <tbody>
           <tr data-ng-repeat="user in vm.users">
             <td>{{user.name}}</td>
           </tr>
         </tbody>
       </table>
     </div>
   </body>
</html>

Putting everything together

Almost ready to go. Let’s hook up everything in app.ts:

/// <reference path='controllers/userClientController.ts' />
 
module meanExample {
     var appModule = angular.module("meanType", []);
     appModule.controller("UserClientController", ["$scope", "$http", ($scope,$http)
         => new MeanUsers.UserClientController($scope, $http)]);
}

Run the application

Once we run the application, we should be greeted with this simple view:

image

We can now enter a name and hit the “+” button. The user “angular” should appear on the list.

image

Let’s check to see what’s happening on the server. Having a look at some node output, we see a post made:

image

And finally, having a look at what’s in MongoDB:

image

 

Great! So we go a (very) basic application working!

Conclusion

Now we have successfully hooked up an application that has a Node/Express back-end, an Angular front-end, and a MongoDB data store. The application itself is very basic, having been used as an opportunity to dig into TypeScript, but is a decent starting point for further investigation. I will continue digging into these concepts, aiming to flesh out the core idea into a more fully-fledged stack for various projects.

Cheers!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s