This article is part of a series of 3 articles
This is the table of contents for this article only, each of the articles in this series has its own table of contents
It has been quite a while since I wrote my last article, I have been busy writting a long series of blob posts on "F# For Beginners", and doing a lot of reading (which I hope to have more blog posts/articles about very soon).
Anyway we digress, so what is this article about. Well it is a small Angular.js Single Page App, demo app that works with ASP MVC / Web Api / SignalR / Azure storage that I have written that is something like twitter but for images.
The basic idea is that you can:
- Create sketches (a bit like paint, but no where near as advanced) which are stored in Azure blob storage
- Choose which friends you want to receive information from (like when they post a new sketch)
- Comment on other peoples sketches
That is it really, but in essence that is all that Twitter is really, you post some text, people follow you, and they may comment on something you posted.
I just like quite visual things, so decided to do it with images instead.
This is NOT a new idea it has been done a million times before (for example Facebook walls / Reddit etc etc), that is not the point of this article.
The point of this article is that it was something fun I could attempt to write that I could share with others. I think there is a fair bit you could get out of it, if you looked into the code. For example the demo code makes use of the following stuff:
- Azure blob storage
- Azure table storage
- Angular.js Single Page app (SPA)
- SignalR with Angular.js
- Using Angular.js with ASP MVC
- Responsive design Bootstrap web site
- There is enough meat in it to make it quite a neat demo application
The basic idea can be laid out in the following few paragraphs
You pick a user to login as from a list of static users. I wanted to use Facebook SDK etc etc, but its banned at work, so it turned out to be easier just to have a static list of users. Once you pick a user to login as all other users in the static list become your friends automatically, lucky you (if only life were that easy...I have like 2 friends I think, and one of them is me, doh).
CLICK FOR BIGGER IMAGE
Your main Sketcher "Actions" hub, from where you can carry out all the other Sketcher actions such as
- Editing your subscriptions
- Creating new Sketches
- Viewing all Sketches
CLICK FOR BIGGER IMAGE
The remaining list of users from the static user list, are available as "your friends" from them you may choose who you will to receive push notifications from when a new sketch is created by them
CLICK FOR BIGGER IMAGE
The Create page is where you will create your sketches.
CLICK FOR BIGGER IMAGE
Here is where you will see everyone (not just you friends but everyones sketches, this is by design), where we show a simple thubnail and the title along with the number of comments. From here you may click to go into that particular Sketch.
CLICK FOR BIGGER IMAGE
And here it what it looks like when viewed on a small size (thanks to Bootstrap this is very easily achieved)
This allows you to view a single sketch and comment on it (providing it's not your own sketch). You will also be able to see everyone elses comments
CLICK FOR BIGGER IMAGE
The browser on the left is Chrome with the user "Sacha Barber" who created the "Black Snake" image, another user on the right handside browser (IE on the right browser) can comment on "Sacha Barbers" "Black Snake" Sketch. As "Sacha Barber" created it, he is not allowed to comment on his own Sketch.
When a different user (one who you have in your subscriptions list) creates a sketch, you will receive a growl like notification popup, that you may click on to quickly navigate to their new Sketch, where you can laugh at their awesome sketch and leave some witty comment
CLICK FOR BIGGER IMAGE
The browser on the left is Chrome with the user "Sacha Barber" who subscribes to "Adam Gill" user Sketches, so when Adam (IE on the right browser) creates a Sketch, "Sacha Barber" in Chrome gets a notification toast popup, which Sacha can then click
I am getting older by the day, and I just don't have the energy I had when I was 8, so I have spared myself some pain and anguish in this area, and have opted to only bother trying stuff in the 2 major stakeholders in the browser wars. Which according to the stats I looked at (http://en.wikipedia.org/wiki/Usage_share_of_web_browsers) boiled down to the following 2 browsers:
- Google Chrome (I used v36)
- Microsoft Internet Explorer (v11)
The main thrust of the article is showcasing technology that may be of interest, not me getting even more gray hair by messing around with Browser quirks, so I make no apologies for this. It works in the 2 browsers listed above just fine, anything else, mehhhh who knows.
The code for this series is hosted on GitHub and can be found right here:
https://github.com/sachabarber/AngularAzureDemo
You will need a couple of things before you can run the demo application these are as follows:
- Visual Studio 2013
- Azure SDK v2.3
- Azure Emulator v2.3
- A will to learn by yourself for some of it
- Patience
I hope you don't mind but I have actually written an Angular.Js article before, so rather than me come up with new and fancy way to say the same things, I have just borrowed some of this basic introduction stuff to Angular.Js from my old article (which is here in case anyone is interested : http://www.codeproject.com/Articles/637430/Angular-js-example-application)
In this section I will discuss some of the BASICS of working with Angular.js. This section will be a mixture of my own words, and text lifted directly from the Angular.js web site. I will not be covering everything that Angular.js does, as that would be more like a book really, and I just do not have that much time. I will however be covering some of the basic Angular.js building blocks, so should you read this article and think "mmm...This Angular stuff intrigues me, where can I learn more", by following the the hyperlinks of course
Each Angular.js application will at some point need to use a Angular.js ng-app
binding within the html, or via some code that does the same job as the declaritive html binding. This code essentialy bootstraps Angular.js and lets it know what context the application is running in. For example you may have the following code:
<div id="outer">
<div id="inner" ng-app="myApp">
<p>{{name}}</p>
</div>
<p>This is not using the angular app, as it is not within the Angular apps scope</p>
</div>
It can be seen that we can tell a particular section of the html to act as an Angular.js application. In this example what this means is that the div with id="inner"
WILL have a section of the html (though there is nothing to stop you making the actual Body tag be the angular app) that is considered to be the Angular.js application, and as such will have full access to the Angular.js application features (which we will discuss below).
Whilst the div with the id="outer"
WILL NOT be considered to be part of the Angular.js application, and as such WILL NOT have ANY access to the Angular.js application features (which we will discuss below).
Services/Factories in Angular.js are much the same as they are in WinForms/WPF or Silverlight. They are little helper classes that may provide functionality that could be used across the application. In strongly typed languages such as C# we would typically make these services implement a particular interface and inject them (via constructor or property injection) into our application code. We would then be able to provide fakes/mocks of these services within our tests, or provide alternative versions if the underlying system changes (for example swapping from Mongo DB to Raven DB storage)
Whilst Angular.js doesn't support interfaces (though you could use TypeScript
for that) it does support the injection of real/fakes services into its code. In fact I would say that one of Angular.js main points is it supports IOC out of the box.
One thing that is important to know with Angular.js Services/Factories is that they are typically singleton instances.
Most applications have a main method which instantiates, wires, and bootstraps the application. Angular apps don't have a main method. Instead modules declaratively specify how an application should be bootstrapped. There are several advantages to this approach:
- The process is more declarative which is easier to understand
- In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
- Additional modules can be loaded in scenario tests, which can override some of the configuration and help end-to-end test the application
- Third party code can be packaged as reusable modules.
- The modules can be loaded in any/parallel order (due to delayed nature of module execution).
http://docs.angularjs.org/guide/module
The recommended approach is to actually split up your modules, such that you may have a structure like this:
- A services module
- A directives module
- A filters module
- Application module(s)
This is how you might define a Angular.js module, the give away is the use of the function "module
" that Angular.js provides
angular.module('xmpl.service', []).
value('greeter', {
salutation: 'Hello',
localize: function(localization) {
this.salutation = localization.salutation;
},
greet: function(name) {
return this.salutation + ' ' + name + '!';
}
}).
value('user', {
load: function(name) {
this.name = name;
}
});
Angular.js was built with dependency injection (IOC) in mind, as such a lot of the infrastructure may be swapped out for mocked versions, or controllers could be tested using mocked services. Showing how to do this, or how to test Angular.js applications in not in the scope of this article. If you want to know that, visit the Angular.js docs, or get a book. Sorry
Following on from the previous module example, this is what a module might look like that took some dependencies, in this case a module that we just defined above, where we use the 2 values 'greeter
' and 'user
' which are both functions available within the 'xmpl.service
' module. This module could be supplied with a mocked version of the 'xmpl.service
' module.
angular.module('xmpl', ['xmpl.service']).
run(function(greeter, user) {
greeter.localize({
salutation: 'Bonjour'
});
user.load('World');
})
Angular.js is primarily a single page application framework, and as such has the concept of view templates that can be applied in response to a certain route being requested.
Routing in Angular.js is actually not that different to routing in things like ASP MVC or even node.js for that matter.
Routing is accomplished by using a prebuild service called $routeProvider, which comes for free as part of Angular.js. It allows the user to configure their routes using a very simple API, which boils down to these 2 functions
when(path, route)
- Where the the
route
object has the following properties
- controller
- template
- templateUrl
- resolve
- redirectTo
- reloadOnSearch
otherwise(params)
Here is a little example
$routeProvider
.when('/products', {
templateUrl: 'views/products.html',
controller: 'ProductsCtrl'
})
.when('/about', {
templateUrl: 'views/about.html'
})
.otherwise({ redirectTo: '/products' });;
There is not too much to say about the view. We have all probably come across html before. That is what the views contain. The only difference being that Angular.js views will contain additional (non standard html) bindings that allow the view template to display data from a Angular.js scope object. The scope object would typically come from a controller (though it is not limited to coming from a controller, it could be inherited, or be created via a directive say).
Here is a small example of a view, notice the bindings used in there, such as the use of ng-model
and ng-repeat
and also the usage of some of Angular.js pre-built fiters, nameley filter
and orderBy
(Please note I will not be covering filters in this article)
Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
{{phone.name}}
<p>{{phone.snippet}}</p>
</li>
</ul>
Controllers are used to define the scope for the views. Scope can be thought of as the variables and functions that the view may use, say by using a ng-click
binding. Here is the controller code that goes with the view template that we just saw.
function PhoneListCtrl($scope) {
$scope.phones = [
{"name": "Nexus S",
"snippet": "Fast just got faster with Nexus S.",
"age": 0},
{"name": "Motorola XOOMâ„¢ with Wi-Fi",
"snippet": "The Next, Next Generation tablet.",
"age": 1},
{"name": "MOTOROLA XOOMâ„¢",
"snippet": "The Next, Next Generation tablet.",
"age": 2}
];
$scope.orderProp = 'age';
It can be seen that the controller defines the following 2 scope properties
phones
: which is a JSON array
orderProp
: which is a single string value
It is possible for a page to made up of a number of controllers. The demo app actually does have 2 controllers active at any one time. More on this later.
Scope is the glue that allows the view and the controllers defined scope object properties/function to bind together. If you have ever done any XAML based tech such as WPF/Silverlight/WinRT you can think of scope as a DataContext
. In fact there are quite a few UI frameworks that have a scope like concept. XAML technologies have DataContext
which would typically be a ViewModel, whilst another popular MVVM JavaScript library Knockout.js also has the idea of scope, and heirarchical scope, which is accessable in binding(s) within the html using various prebuilt key words.
Angular.js also supports nested/heirarchical scopes, which can get a bit confusing at times. I personally found that one of the best ways to work with Angular.js and its scopes is to install the Batarang Chrome addin, which has a nice way of allowing youto drill into scopes using a scope inspector (kind of like Snoop for WPF or SilverlightSpy for Silverlight)
This diagram may help solidify the concept of view-controller-scope.
Click image for larger version
Angular.js makes use of a pretty novel concept, which are known as directives. Directives are clever chaps, that actually allow you to create extra attributes, or even new DOM fragments. This is all controlled by applying certain constraints to a directive, such that you may wish to state that a certain directive may only be used as an attribute, or that it can only be used as an element. You can sort of think of directives as custom controls.
Directives also follow the normal Angular.js rules, in that they support dependency injection, and they are also scope aware.
One of the best bits of information I came across when writing this article was this one by Bernardo Castilho : http://www.codeproject.com/Articles/607873/Extending-HTML-with-AngularJS-Directives, I urge you to read that, it is an excellent article, and by the end of it you will totally get directives.
Angular.js will work with jquery quite happily (its all just JavaScript at the end of the day), so one could make use of jquery for making REST calls using the familiar
However Angular.js has more powerful tools in its arsenal such as
The $http service is a core Angular service that facilitates communication with remote HTTP servers via the browser's XMLHttpRequest object or via JSONP.
For unit testing applications that use $http service, see $httpBackend mock.
For a higher level of abstraction, please check out the $resource service.
The $http API is based on the deferred/promise APIs exposed by the $q service. While for simple usage patterns this doesn't matter much, for advanced usage it is important to familiarize yourself with these APIs and the guarantees they provide.
Here is some typical usage for a $http service
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
}).
error(function(data, status, headers, config) {
});
$resource provides an even higher level abstraction than the $http service. It provides a factory which creates a resource object that lets you interact with RESTful server-side data sources.
The returned resource object has action methods which provide high-level behaviors without the need to interact with the low level $http service.
It requires that you have the ngResource module installed.
Here is a small example of typical usage, which I am sure you will agree is pretty compact
var User = $resource('/user/:userId', {userId:'@id'});
var user = User.get({id:123}, function() {
user.abc = true;
user.$save();
});
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
https://docs.angularjs.org/api/ngResource/service/$resource up on date 11/08/14
That said, I personally prefer to hook up actions, such that I can show custom wait spinners and warnings etc etc
It should be noted that you may also add custom functions here should you need them, but in some cases you will find you really need the flexibility of the $http service, so will use that instead.
Anyway that concludes the Angular.js basics, like I say I have borrowed a lot of this section from my previous article, which I hope people don't mind too much. Even though it is re-hashing an older article, I can asure you all that the material contained in the attached demo code is nothing like the old article code, it is completely new stuff.
In this article we talked about what the actual demo app does, and we also paved the way for disecting the demo app (though we did not actual dive into any of the demo apps workings), such that some of the Angular.Js bits would not come as a suprise, when we do dive into them.
Next time we will look into the demo app, and be disecting 2 of its main workflows, those will be:
- Login
- Subscription Management
That is all I wanted to say in this article. There may be those amongst you who are dissapointed that this article doesn't have everything, truth is it would have just been too big, and I just felt it was better suited to more than 1 article, I decided to break it down into 3 articles:
Never the less I hope the overview in this article and the Angular.Js primer gives you a taste of what is to come in the next article or 2.
If you like what you have seen, a vote or comment is most welcome.