Booktrackr Web Client Part II - AngularJS Setup
22 May 2016Last time we installed the main tools we’ll need for working with front end assets, NodeJS and Gulp. This time around, we’ll install some Gulp plugins and implement the first vestiges of our AngularJS Booktrackr web client.
Install AngularJS
Since we took the time to set up Bower, installing AngularJS is pretty simple. We simply run bower install angular angular-route —save
, and Bower will download those to src/main/resource/static/bower_components
.
A Minimal AngularJS app
The index.html
The first part of creating an AngularJS application is to define the main page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Booktrackr</title>
<!-- bower:css -->
<!-- endbower -->
<!-- inject:css -->
<!-- endinject -->
</head>
<body ng-app="booktrackrApp">
<div class="container" ng-view></div>
<!-- bower:js -->
<!-- endbower -->
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
The things to note here are the ng-app
directive on the body
tag and the ng-view
directive on the <div>
element More on the inject
and bower
comments later.
The app.js
Now we need to set up our Angular app. Create a file src/main/resources/app/js/app.js
:
(function () {
'use strict';
angular.module('booktrackrApp', ['ngRoute']);
angular.module('booktrackrApp').config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/home.html',
controller: 'HomeController',
controllerAs: 'vm'
});
}]);
})();
A few things to note:
- We’re wrapping this in an IIFE in order to prevent global namespace clashes. This will help us keep our sanity when we start to concatenate files.
- We’re using the Angular setter syntax (
angular.module('booktrackrApp', ['ngRoute']);
) to declare our module - We’re adding a
/
route that will render the page/partials/home.html
and is controlled byHomeController
. There’s nothing special about those two files, but have a look at them in the pull request so you can see how they work.
A great resource for understanding how to write good Angular code is John Papa’s Angular Style Guide, which I highly recommend you check out.
Configure Gulp to Inject required JS files.
Let’s set up a little bit more infrastructure to inject both third party and our custom front end assets so that this gets done automatically.
Install Dependencies
We need to install a few more Node modules so that we can set up some new tasks in our gulpfile.js
:
gulp-angular-filesort
gulp-inject
run-sequence
wiredep
Remember to pass —save
when you run npm install
for those modules so that they get saved to the package.json
file.
Update Gulpfile.js
The wiredep
task.
Wiredep is a Node module that will read your bower.json
file and inject the required files into our index.html
file. This is useful because if we add a new dependency, we don’t need to remember to add another <script>
or <link>
tag into our DOM. Furthermore, as we’ll see later in the series, we can also use wiredep
in conjuction with other Node modules to minify and concatenate our front end assets.
Here’s what the wiredep
task looks like in gulpfile.js
:
gulp.task('wiredep', function () {
return gulp.src('src/main/resources/static/index.html')
.pipe(wiredep({
exclude: [
'bower_components/bootstrap/dist/js/' // use ui-bootstrap
],
overrides: { // see discussion here https://github.com/twbs/bootstrap/issues/16663
bootstrap: {
main: [
"dist/css/bootstrap.css"
]
}
}
}))
.pipe(gulp.dest('src/main/resources/static'));
});
We’re excluding the Bootstrap Javascript because it doesn’t play nicely with Angular, and due to some changes in the way Bower processes resources (see here for more discussion), we have to override Bootstrap’s configuration to inject the CSS files.
The inject
task
gulp-inject
is similar to the wiredep
task but this one will inject the JS and CSS files that we write into our index.html
. Here’s how the task is configured:
gulp.task('inject', function () {
return gulp.src('src/main/resources/static/index.html')
.pipe(inject(
gulp.src('src/main/resources/static/app/js/**/*.js')
.pipe(angularFilesort()), {relative: true}
))
.pipe(gulp.dest('src/main/resources/static'));
});
Two things of note are that we are using the angularFilesort()
function so that the files will be injected in the order they need to be for the application to bootstrap itself correctly. The other thing to note is that we are using relative: true
so that the paths to the resources will work right with Spring Boot’s static resource handling.
Make sure you look at the gulpfile.js
on GitHub or the changes in the pull request that accompanies this post to get all of the changes.
Wrap Up
The only other things we need to do are add a HomeController
to serve our index.html
and update ourSecurityConfig
class to permit unauthenticated requests to our JS files, both of which you can look at in the PR. If you run the wiredep
and inject
tasks and then run the application, you should see the markup from home/partials.html
.