angular.js example application from codeproject

14
10,234,036 members (51,916 online) 317 Sign out vartmaan Tweet Tweet 54 home quick answers discussions features community help Search for articles, questions, tips Articles » Web Development » Client side scripting » General Article Browse Code Stats Revisions (3) Alternatives Comments & Discussions (45) Add your own alternative version About Article An example application using angular/Rx for JavaScript/Web Sockets/jQuery Type Article Licence CPOL First Posted 14 Aug 2013 Views 46,926 Bookmarked 105 times C# Javascript CSS .NET Architect Dev ADO.NET , + Top News 30 years ago Windows was first released, see how much it has changed Get the Insider News free each morning. Related Videos Related Articles ArcPong Angular: The DOM API You Have Been Waiting For Use Backbone.js to make a structured web application AngularJS Single Page Application with WebAPI and Upida backend Data with AngularJS 404 Hall of Fame - Celebrating the most notorious http error code! Extending HTML with AngularJS Directives Next Rate: Like 18 Angular.js example application By Sacha Barber, 5 Sep 2013 Demo application code : Here is a link where you can download the : Demo Application Table Of Contents Introduction The Demo App Overview Angular.Js Introduction Apps Services Modules Dependency Injection Routing Views Controllers Scope Directives The Publisher The Angular.js Website Require.js Usage The Main App Setup The Routing The Root Page LiveUpdatesService LocalStorageService ImageService UtilitiesService Draggable Directive Resizable Directive Root Controller Root View The Favourites Page Favs Controller Favs View ColorBox Directive The About Page That's It Introduction This article is my first one for quite a while, there is a reason for that but I will not bore you all with that. Anyway I have written this article after a little time off. So what does it do, what is this article about? I decided to spend a bit of time to learn a bit more about a popular web MVC framework by our friends at Google called Angular.js, which is a JavaScript MVC framework, which is a bit of departure for me from my usual XAML influenced world. It is however good to try things out to get an appreciation of how you would do things in different languages/environments (my old mentor Fredrik Bornander (AKA the Swede) told me that), so I decided to take Angular.js for a spin. This article will talk about some of the fundamental ideas behind Angular.js, and shall then focus on the specifics of the demo application that I have created to go along with this article. Before we get into the actual article I will just breifly (not too techie just yet, though I know you lot will want to see that, and it will come don't worry) talk about what the demo app does in plain terms, so you know how to drive the thing yourself when you download it. The Demo App Overview There are 2 parts to the attached demo app Publisher This is a standard WPF project, as such produces a EXE file that can be run. I will not be spending too much time talking about the publisher in this article, as it is not the important part of the article, it is simply a vehicle to demonstrate stuff within the Angular.js web site. Anyway what the the publisher does it to allow user to click a image, when the user clicks an image a message is sent to the Angular.js web site using web sockets (more on this later). In a nutshell that is all the publisher does. Website The Angular.js web site, is where the fun stuff happens (at least in my opinion). The Angular.js web site essentially carries out these tasks When on the root page, the Angular.js will listen to messages sent via the WPF publisher over a web socket, which then gets broadcast internally using the Reactive Extensions for JavaScript to anyone interested, which in this article is essentially just the root page. The root page will display an image tile for each allowable message received. The image tile may be resized and dragged around thanks to some jQuery UI love. The user may then choose to save the image tile to their 5.00 (42 votes) Sign up for our free weekly Web Developer Newsletter. × articles Angular.js example application - CodeProject 29-11-2013 http://www.codeproject.com/Articles/637430/Angular-js-example-application 1 / 14

Upload: rohit-gupta

Post on 26-Nov-2015

243 views

Category:

Documents


4 download

DESCRIPTION

Example Angular

TRANSCRIPT

  • 10,234,036 members (51,916 on lin e) 317 Sign ou t

    vartmaan

    TweetTweet 54

    home quick answers discussions features community help Search fo r articles, qu estion s, tip s

    Articles Web Development Client side scripting General

    Article

    Browse Code

    Stats

    Revisions (3)

    Alternatives

    Comments &Discussions (45)

    Add your ownalternative version

    About Article

    An example applicationusing angular/Rx forJavaScript/WebSockets/jQuery

    Type Article

    Licence CPOL

    First Posted 14 Aug 2013

    Views 46,926

    Bookmarked 105 times

    C# Javascript CSS .NET

    Architect Dev ADO.NET ,

    +

    Top News

    30 years ago Windows wasfirst released, see howmuch it has changed

    Get the Insider News free eachmorning.

    Related Videos

    Related ArticlesArcPong

    Angular: The DOM API YouHave Been Waiting For

    Use Backbone.js to make astructured web application

    AngularJS Single PageApplication with WebAPI andUpida backend

    Data with AngularJS

    404 Hall of Fame - Celebratingthe most notorious http errorcode!

    Extending HTML with AngularJSDirectives

    Next

    Rate:Like 18

    Angular.js example applicationBy Sacha Barber, 5 Sep 2013

    Demo application code : Here is a link where you can download the : Demo Application

    Table Of Contents

    IntroductionThe Demo App OverviewAngular.Js Introduction

    AppsServicesModulesDependency InjectionRoutingViewsControllersScopeDirectives

    The PublisherThe Angular.js Website

    Require.js UsageThe Main App SetupThe RoutingThe Root Page

    LiveUpdatesServiceLocalStorageServiceImageServiceUtilitiesServiceDraggable DirectiveResizable DirectiveRoot ControllerRoot View

    The Favourites Page

    Favs ControllerFavs ViewColorBox Directive

    The About Page

    That's It

    IntroductionThis article is my first one for quite a while, there is a reason for that but I will not bore you all with that.Anyway I have written this article after a little time off. So what does it do, what is this article about?

    I decided to spend a bit of time to learn a bit more about a popular web MVC framework by our friends atGoogle called Angular.js, which is a JavaScript MVC framework, which is a bit of departure for me from my usualXAML influenced world. It is however good to try things out to get an appreciation of how you would do thingsin different languages/environments (my old mentor Fredrik Bornander (AKA the Swede) told me that), so Idecided to take Angular.js for a spin.

    This article will talk about some of the fundamental ideas behind Angular.js, and shall then focus on the specificsof the demo application that I have created to go along with this article.

    Before we get into the actual article I will just breifly (not too techie just yet, though I know you lot will want tosee that, and it will come don't worry) talk about what the demo app does in plain terms, so you know how todrive the thing yourself when you download it.

    The Demo App OverviewThere are 2 parts to the attached demo app

    Publisher

    This is a standard WPF project, as such produces a EXE file that can be run. I will not be spending too muchtime talking about the publisher in this article, as it is not the important part of the article, it is simply a vehicleto demonstrate stuff within the Angular.js web site. Anyway what the the publisher does it to allow user to clicka image, when the user clicks an image a message is sent to the Angular.js web site using web sockets (more onthis later). In a nutshell that is all the publisher does.

    Website

    The Angular.js web site, is where the fun stuff happens (at least in my opinion). The Angular.js web siteessentially carries out these tasks

    When on the root page, the Angular.js will listen to messages sent via the WPF publisher over a websocket, which then gets broadcast internally using the Reactive Extensions for JavaScript to anyoneinterested, which in this article is essentially just the root page.

    The root page will display an image tile for each allowable message received. The image tile may be resized anddragged around thanks to some jQuery UI love. The user may then choose to save the image tile to their

    5.00 (42 votes)

    Sign up for our free weekly Web Developer Newsletter.

    articles

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 1 / 14

  • Directives

    Displaying a Custom Dialog inWPF Before the MainApplication Window is Shown

    Examples to create yourConferencing System in .NET,C# VOIP & Video ConferencingSystems using H.323 and TAPI 3

    Working with the Web BrowserControl in Visual Studio 2005 -IE7Clone.

    App_Offline.htm

    Run only one instance from youprogram

    JavaScript Frameworks andResources

    Sending and playingmicrophone audio over network

    Spell checking in MicrosoftAccess 2003 applications

    Debug your ASP.NETApplication while Hosted on IIS

    Carcassonne scoring boardapplication

    A Walkthrough to ApplicationState

    Processing Global Mouse andKeyboard Hooks in C#

    How To Create a Self-Restartable Application

    Related Research

    Fine-Tuning the Engines of SMBGrowth: 4 strategies for growing

    your business

    Custom API Management forthe Enterprise: Learn how to

    build a successful API strategy[Webinar]

    favourites, which will cause ALL the information about the image tile to be saved to HTML 5 local storage. Thisinformation includes size, position etc etc, so when the user comes back to the root page, their favourites (theones they saved) should appear exactly as they were before. The user may also decide to remove image tilesfrom their favourites from the root page.

    The user may also choose to navigate to a favourites page that will display some thumbnail images oftheir HTML 5 local storage persisted favourites. These thumbnails may be clicked on to show a prettystandard ColorBox (Lightbox etc etc type thing) jQuery plugin.

    The user may also choose to a view static about page, which I simply added to make enough routes tomake things more worthwhile when demonstating the routing within Angular.js

    So in plain terms that is all there is to it, this image may help to solidify what I just stated in words, picture says1000nd words and all that:

    This is what the 2 parts of this articles demo code should look like when they are running correctly:

    Click image for larger version

    IMPORTANT NOTE:

    You should really ensure that you follow these steps to run the demo code successfully

    1. If you find that some of the Publisher.Wpf projects references can not be found, I haveincluded them in a "Lib" folder where you can simply re-reference them from

    2. You should ensure that the Publisher.Wpf project is run up first and that it is displaying allthe images. This can be done by building the Publisher.Wpf project to an EXE and simplyfinding the EXE in your file system and double clicking it to run (or use Visual Studio to runup an instance in DEBUG)

    3. You should then run the Angular web site, make sure that you have Index.html set as startpage in Visual Studio and then use Visual Studio to run the Angular web site

    Angular.Js IntroductionIn this section I will discuss some of the BASICS of working with Angular.js. This section will be a mixture of myown words, and text lifted directly from the Angular.js web site. I will not be covering everything that Angular.jsdoes, as that would be more like a book really, and I just do not have that much time. I will however becovering some of the basic Angular.js building blocks, so should you read this article and think "mmm...ThisAngular stuff intrigues me, where can I learn more", by following the the hyperlinks of course

    AppsEach Angular.js application will at some point need to use a Angular.js ng-app binding within the html, or viasome code that does the same job as the declaritive html binding. This code essentialy bootstraps Angular.jsand lets it know what context the application is running in. For example you may have the following code:

    Co llapse | Copy Code

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 2 / 14

  • {{name}} This is not using the angular app, as it is not within the Angular apps scope

    It can be seen that we can tell a particular section of the html to act as an Angular.js application. In this examplewhat this means is that the div with id="inner" WILL have a section of the html (though there is nothing tostop 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 assuch WILL NOT have ANY access to the Angular.js application features (which we will discuss below).

    ServicesServices in Angular.js are much the same as they are in WinForms/WPF or Silverlight. They are little helperclasses that may provide functionality that could be used across the application. In strongly typed languagessuch as C# we would typically make these services implement a particular interface and inject them (viaconstructor or property injection) into our application code. We would then be able to provide fakes/mocks ofthese services within our tests, or provide alternative versions if the underlying system changes (for exampleswapping from Mongo DB to Raven DB storage)

    Whilst Angular.js doesn't support interfaces (though you could use TypeScript for that) it does support theinjection of real/fakes services into its code. In fact I would say that one of Angular.js main points is it supportsIOC out of the box.

    ModulesMost applications have a main method which instantiates, wires, and bootstraps the application. Angularapps don't have a main method. Instead modules declaratively specify how an application should bebootstrapped. There are several advantages to this approach:

    The process is more declarative which is easier to understandIn 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 andhelp end-to-end test the applicationThird 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 moduleA directives moduleA filters moduleApplication module(s)

    This is how you might define a Angular.js module, the give away is the use of the function "module" thatAngular.js provides

    Co llapse | Copy Code

    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; } });

    Dependency InjectionAngular.js was built with dependency injection (IOC) in mind, as such a lot of the infrastructure may beswapped out for mocked versions, or controllers could be tested using mocked services. Showing how to dothis, or how to test Angular.js applications in not in the scope of this article. If you want to know that, visit theAngular.js docs, or get a book. Sorry

    Following on from the previous module example, this is what a module might look like that took somedependencies, 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 suppliedwith a mocked version of the 'xmpl.service' module.

    Co llapse | Copy Code

    angular.module('xmpl', ['xmpl.service']). run(function(greeter, user) { // This is effectively part of the main method initialization code greeter.localize({ salutation: 'Bonjour' }); user.load('World'); })

    RoutingAngular.js is primarily a single page application framework, and as such has the concept of view templates thatcan 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 thatmatter.

    Routing is accomplished by using a prebuild service called $routeProvider, which comes for free as part ofAngular.js. It allows the user to configure their routes using a very simple API, which boils down to these 2functions

    1. when(path, route)

    Where the the route object has the following properties

    controllertemplatetemplateUrl

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 3 / 14

  • resolveredirectToreloadOnSearch

    2. otherwise(params)

    Here is a little example

    Co llapse | Copy Code

    $routeProvider .when('/products', { templateUrl: 'views/products.html', controller: 'ProductsCtrl' }) .when('/about', { templateUrl: 'views/about.html' }) .otherwise({ redirectTo: '/products' });;

    ViewsThere is not too much to say about the view. We have all probably come across html before. That is what theviews 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 wouldtypically come from a controller (though it is not limited to coming from a controller, it could be inherited, or becreated 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 Iwill not be covering filters in this article)

    Co llapse | Copy Code

    Search: Sort by:

    Alphabetical Newest

    {{phone.name}} {{phone.snippet}}

    ControllersControllers are used to define the scope for the views. Scope can be thougt of as the variables and functionsthat the view may use, say by using a ng-click binding. Here is the controller code that goes with the viewtemplate that we just saw.

    Co llapse | Copy Code

    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 arrayorderProp : which is a single string value

    ScopeScope is the glue that allows the view and the controllers defined scope object properties/function to bindtogether. If you have ever done any XAML based tech such as WPF/Silverlight/WinRT you can think of scope asa DataContext. In fact there are quite a few UI frameworks that have a scope like concept. XAML technologieshave DataContext which would typically be a ViewModel, whilst another popular MVVM JavaScript libraryKnockout.js also has the idea of scope, and heirarchical scope, which is accessable in binding(s) within the htmlusing various prebuilt key words.

    Angular.js also supports nested/heirarchical scopes, which can get a bit confusing at times. I personally foundthat one of the best ways to work with Angular.js and its scopes is to install the Batarang Chrome addin, whichhas a nice way of allowing youto drill into scopes using a scope inspector (kind of like Snoop for WPF orSilverlightSpy for Silverlight)

    This diagram may help solidify the concept of view-controller-scope.

    Click image for larger version

    Directives

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 4 / 14

  • Angular.js makes use of a pretty novel concept, which are known as directives. Directives are clever chaps, thatactually allow you to create extra attributes, or even new DOM fragments. This is all controlled by applyingcertain constraints to a directive, such that you may wish to state that a certain directive may only be used asan 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 alsoscope 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 readthat, it is an excellent article, and by the end of it you will totally get directives.

    Anyway that concludes the Angular.js basics, it's now on with the actual demo application code walkthrough.

    The PublisherAs I have previously stated the publisher is a WPF application (as such it is a runnable EXE), that is not really themain thrust of this article. The main points about the publisher are:

    1. That is uses the awesome Fleck WebSocket library to talk to the Angular.js web site2. That is has a Win8 type panorama, so you can scroll around using the mouse

    Here is what the WPF publisher should look like when it is running:

    Now on to the important part, the web socket code.

    Co llapse | Copy Code

    public class WebSocketInvoker : IWebSocketInvoker{ List allSockets = new List(); WebSocketServer server = new WebSocketServer("ws://localhost:8181");

    public WebSocketInvoker() { FleckLog.Level = LogLevel.Debug; server.Start(socket => { socket.OnOpen = () => { Console.WriteLine("Open!"); allSockets.Add(socket); }; socket.OnClose = () => { Console.WriteLine("Close!"); allSockets.Remove(socket); }; socket.OnMessage = Console.WriteLine; }); }

    public void SendNewMessage(string jsonMessage) { foreach (var socket in allSockets) { socket.Send(jsonMessage); } }}

    This is all there is to that part actually, pretty cool huh (all thanks to the Fleck WebSocket library). Now I realisethat there may be some of you out there that are like why didn't you use SignalR, well I could have, but thatwould have been a pretty different article, for this one I wanted to concentrate purely on the web client side ofthings, so chose to use a raw web socket, and the Fleck WebSocket library fits that bill perfectly.

    In this code the SendNewMessage will be called when a user clicks an image, and the name of the imageclicked will be sent via the web socket to the Angular.js web site. The Angular.js web site, has a copy of all thepossible images, as I did not want to get into complex POST operations of files, and obviously a web servercan't show a local file (which would be a security risk in my (and any others) opinion), so I opted for shared filesthat the publisher and the Angular.js web site both know about for the purpose of this demo application/article.

    The Angular.js WebsiteThis section will discuss the nitty gritty about the attached demo code Angular.js web site. Hopefully if you havegot to this point, some of the stuff I mentioned above will begin to make sense when you see some code.

    Require.js Usage

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 5 / 14

  • Before I starting looking into Angular.js I was looking into using Require.js, which is a module loadingframework for JavaScript, which allows you to specify your dependencies and preferred module load order. Iwrote about this in another article, which you can read here: Modular Javascript Using Require.Js

    I have kind of built apon that a bit more in this article (with a little bit of a kick start with the source code thatcomes with the Angular.js O'Reilly book : https://github.com/shyamseshadri/angularjs-book)

    So that is where you can do more reading around this subject if you want to, but let's crack on and see whatthe Require.js element of the attached Angular.js website looks like shall we.

    It starts with this sort of code in the main Angular.js page (Index.html):

    See index.html

    Co llapse | Copy Code

    .....

    This is standard Require.js code that tells Require.js which is the main bootstrap code file that it should run. Itcan be seen that this is scripts/main, so let's have a look at that now shall we

    See scripts\main.js

    Co llapse | Copy Code

    // the app/scripts/main.js file, which defines our RequireJS configrequire.config({ paths: { angular: 'vendor/angular.min', jqueryUI: 'vendor/jquery-ui', jqueryColorbox: 'vendor/jquery-colorbox', jquery: 'vendor/jquery', domReady: 'vendor/domReady', reactive: 'vendor/rx' }, shim: { angular: { deps: ['jquery', 'jqueryUI', 'jqueryColorbox'], exports: 'angular' }, jqueryUI: { deps: ['jquery'] }, jqueryColorbox: { deps: ['jquery'] } }});

    require([ 'angular', 'app', 'domReady', 'reactive', 'services/liveUpdatesService', 'services/imageService', 'services/localStorageService', 'controllers/rootController', 'controllers/favsController', 'directives/ngbkFocus', 'directives/draggable', 'directives/resizable', 'directives/tooltip', 'directives/colorbox' // Any individual controller, service, directive or filter file // that you add will need to be pulled in here.], function (angular, app, domReady) { . . . .

    });

    There is quite a bit going on here.It does however boil down to 3 parts

    1. We configure Require.js with the paths of where the JavaScript files are2. We configure a preferred load order for Require.js by using the Require.js shim. The shim essentially sets

    up the dependencies for the libraries to load3. We then use Require.js [Require] to tell the Angular.js application what dependencies we would like to be

    satisfied.

    I have also used Require.js to satisfy the demo applications controller requirements. An example of which is asfollows:

    Co llapse | Copy Code

    define(['controllers/controllers', 'services/imageService', 'services/utilitiesService', 'services/localStorageService'], function (controllers) { controllers.controller('FavsCtrl', ['$window', '$scope', 'ImageService', 'UtilitiesService', 'LocalStorageService', function ( $window, $scope, ImageService, UtilitiesService, LocalStorageService) { ...... ...... ...... ...... ......

    }]);});

    The Main App SetupSee scripts\main.js

    Now that you have seen the main bootstrapping code (which is mainly taken up by the Require.jsconfiguration), lets just have a quick look at the actual Angular.js bootstrapping bit.

    This is the bit that we discussed right at the start of this article, you know the bit that actual makes theattached code an "Angular.js" application.

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 6 / 14

  • That part is as follows:

    Co llapse | Copy Code

    function (angular, app, domReady) { 'use strict'; app.config(['$routeProvider', function ($routeProvider) { .... .... .... }]); domReady(function () { angular.bootstrap(document, ['MyApp']);

    // The following is required if you want AngularJS Scenario tests to work $('html').addClass('ng-app: MyApp'); });}

    This bootstrapping does 2 things:

    1. It sets up the available valid routes, which we will be looking at next2. It relies on a special Angular.js addin called "DomReady" which works much the same way as jQuery and

    its ready() event. After the dom is ready the "HTML" element is attributed up to make it act as theAngular.js application.

    There is also the question of where the "MyApp" module comes from. Who creates that prior to it beingbootstrapped here?

    The answer to that is that is lives in its own file "app.js" which looks like this

    See scripts\app.js

    Co llapse | Copy Code

    // The app/scripts/app.js file, which defines our AngularJS appdefine(['angular', 'controllers/controllers', 'services/services', 'filters/filters', 'directives/directives'], function (angular) { return angular.module('MyApp', ['controllers', 'services', 'filters', 'directives']);});

    The RoutingSee scripts\main.js

    For the demo application there are 3 valid routes Root/Favs/About. Each of these is configured using thestandard Angular.js $routeProvider service, where all the set up code is done within the boostrapping filemain.js.

    Co llapse | Copy Code

    unction ($routeProvider) { $routeProvider .when('/', { templateUrl: 'views/root.html', controller: 'RootCtrl' }) .when('/favs', { templateUrl: 'views/favs.html', controller: 'FavsCtrl' }) .when('/about', { templateUrl: 'views/about.html' }).otherwise({ redirectTo: '/' });;}

    I think it is pretty obvious from that there are 3 routes as stated above and how they are configured. So I wilnot say any more on that.

    The Root PageThis is the most complex page within the demo web site I have put together, as it brings in lots of differentthings together.

    So what does this page do exactly?

    The idea is that there is a service called "LiveUpdatesService" that listens to the client end of the WebSocket that the WPF publisher is pushing data out on. The LiveUpdatesService uses the reactive extensionsfor JavaScript to provide a stream of data that may be subscribed to.

    The root page will subscribe to this pulished stream, and every time it sees a new entry it will add a new jQueryUI Draggable/Resizable UI element, providing it has not already got an element with the same image nameshown.

    It also allows the user to save the images to HTML 5 local storage and to remove them from local storage too.If there are items aready within local storage theirs details are used as the initial start state for the Root page. Ihave to say this looks cool, as all the information is persisted, so it remembers the sizes, locations, ZIndex, so itcomes back exactly how you saved it.

    So in general terms that is what the root page does.

    This is what the root page looks like

    Click image for larger version

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 7 / 14

  • So that is what it looks like, want to see some code?

    LiveUpdatesService

    This is the service that listens for the incoming data from the publisher web socket, and also pushes the newlyrecieved web socket data out, via a reactive extensions for JavaScript Subject object. Here is the code for theservice:

    Co llapse | Copy Code

    define(['services/services'], function (services) { services.factory('LiveUpdatesService', ['$window', function (win) {

    var subject = new Rx.Subject(); if ("WebSocket" in window) { // create a new websocket and connect var ws = new WebSocket('ws://localhost:8181/publisher', 'my-protocol');

    // when data is comming from the server, this metod is called ws.onmessage = function (evt) { subject.onNext(evt.data); };

    // when the connection is established, this method is called ws.onopen = function () { win.alert('Websocket connection opened'); };

    //// when the connection is closed, this method is called ws.onclose = function () { subject.onError('Websocket connection closed, perhaps you need to restart the Publisher, and refresh web site'); }; }

    return {

    publishEvent: function (value) { subject.onNext(value); }, eventsStream: function () { return subject.asObservable(); } }; }]); });

    And here is the root controller code that make use of the reactive extension Subjects stream, where we firstcheck to see whether we have seen an item with the same name before, and if we have simply show a messageto the user (note that we DO NOT use window directly, but rather use a $window angular service (which maybe more easily mocked)).

    If we have not seen the image name before, a new item is created using the ImageService which we positionrandomly

    Co llapse | Copy Code

    LiveUpdatesService.eventsStream().subscribe( function (data) { if ($location.path() == '/') { var idx = $scope.imageitems.propertyBasedIndexOf('name', data); if (idx >= 0) { $window.alert('An item with that name has already been added'); } else { var randomLeft = UtilitiesService.getRandomInt(10, 600); var randomTop = UtilitiesService.getRandomInt(10, 400); var randomWidth = UtilitiesService.getRandomInt(100, 300); var randomHeight = UtilitiesService.getRandomInt(100, 300);

    $scope.imageitems.push(ImageService.createImageItem( data, randomLeft, randomTop, randomWidth, randomHeight, false)); $scope.$apply(); } } }, function (error) { $window.alert(error); });

    LocalStorageService

    This service is responsible for persisting/fetching data items from HTML 5 local storage. I think this code ispretty self explanatory, so I will leave it at that:

    Co llapse | Copy Code

    define(['services/services'], function (services) { services.factory('LocalStorageService', [ function () {

    return { isSupported: function () { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } }, save: function (key, value) { localStorage[key] = JSON.stringify(value); }, fetch: function (key) { return localStorage[key]; }, parse: function(value) { return JSON.parse(value); },

    clear: function (key) { localStorage.removeItem(key); } }; }]); });

    ImageService

    This service simply aids in the creation of ImageItem objects for the Root page and FavItem objects for theFavs page.

    Co llapse | Copy Code

    function ImageItem(name, left, top, width, height, isFavourite) {

    var self = this;

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 8 / 14

  • self.name = name; self.left = left; self.top = top; self.width = width; self.height = height; self.isFavourite = isFavourite;

    self.styleProps = function () { return { left: self.left + 'px', top: self.top + 'px', width: self.width + 'px', height: self.height + 'px', position: 'absolute' }; }; return self;};

    function FavImageItem(name) {

    var self = this; self.name = name; return self;};

    define(['services/services'], function (services) { services.factory('ImageService', [ function () { return { createImageItem: function (name, left, top, width, height, isFavourite) { return new ImageItem(name, left, top, width, height, isFavourite); }, createFavImageItem: function (name) { return new FavImageItem(name); } }; }]); });

    One important thing to note is how the dynamic CSS is done in Angular.js. To achieve dynamic CSS that isupdated when objects change you need to provide a function to call, which is what you can see here in thestyleProps() function:

    Co llapse | Copy Code

    self.styleProps = function () { return { left: self.left + 'px', top: self.top + 'px', width: self.width + 'px', height: self.height + 'px', position: 'absolute' };};

    The markup that uses this as follows, which means when ever an update is done on the JSON object the CSS isupdated too, and the html reflects this. This was not that easy to find out, so make sure you read this bit a fewtimes, solidify that knowledge, wedge it in there good and hard

    Co llapse | Copy Code

    ng-style="imageitems[$index].styleProps()"

    UtilitiesService

    This service provides the following functions:

    Adds a propertyBasedIndexOf() to arrays, which allows an array to be searched for a particular itemproperty where the index will be returnedgetRandomInt() : which is used to get a random x/y point to place new image items at the 1st timethey are showndelayedAlert() : shows an alert after some delay time

    Here is the code:

    Co llapse | Copy Code

    define(['services/services'], function (services) { services.factory('UtilitiesService', [ function () {

    var initialised = false;

    return { addArrayHelperMethods: function () { if (!initialised) { initialised = true; Array.prototype.propertyBasedIndexOf = function arrayObjectIndexOf(property, value) { for (var i = 0, len = this.length; i < len; i++) { if (this[i][property] === value) return i; } return -1; }; } }, getRandomInt: function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; },

    delayedAlert: function(message) { setTimeout(function () { $window.alert(message); }, 1000); } }; }]); });

    Draggable Directive

    To achieve the dragging I already knew I had to use the jQuery UI library, but when working with Angular.js,there is a definate Angular.js way, and littering your controller code with DOM changing jQuery code is mostcertainly NOT the Angular.js way. So what option does that leave us. Well that is really where Angular.jsdirectives fit, they are designed to replace and enhance the DOM, that is what directives do best.

    So anytime you need to alter the DOM directly (not through scope changes) you should be thinking aboutusing Angular.js directives.

    So all that said, it turs out to be a simple matter to create a small jQuery UI Angular.js directive, which can beseen in the .... table tags in the markup.

    Here is the draggable directives code, where you can see that this is restricted to attribute usage, and simplydelegates the work to the actual jQuery UI (which was referenced as a requirement within the Require.jsconfiguration, so we know its loaded ok, otherwise the Angular.js would not have started, as it has jQuery UI as

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 9 / 14

  • a dependency within the Require.js configurtion).

    One thing worth mentioning here is that once the drag has finished I wanted to inform the controller of thenew position values, such that they could be reflected in the styling. Now since the positioning is done outsideof an Angular.js controllers scope (as it is done via the inbuilt jQuery UI code), we need to get the draggabledirective to update the controller scope, such that it knows something outside of it has changed one of itsvariables. Luckily the jQuery UI draggable widget provides a nice callback that we can make use of, which weuse and then tell the Angular.js controller's scope that something has changed, this is done using the Angular.js$scope.apply() which is used for this purpose

    Co llapse | Copy Code

    define(['directives/directives'], function (directives) { directives.directive('draggable', ['$rootScope', function ($rootScope) { return { restrict: 'A', //may need the model to be passed in here so we can apply changes to its left/top positions link: function (scope, element, attrs) {

    element.draggable( { stop: function (event, ui) { scope.$apply(function() { scope.updatePosition( scope.imageitem.name, { left: ui.position.left, top: ui.position.top } ); }); } }); } }; }]);});

    Where this is the controller code that gets called when the directive calls into the controller's scope

    Co llapse | Copy Code

    // NOTE: $scope.$apply is called by the draggable directive$scope.updatePosition = function (name, pos) { var idx = $scope.imageitems.propertyBasedIndexOf('name', name); var foundItem = $scope.imageitems[idx]; foundItem.left = pos.left; foundItem.top = pos.top;};

    Resizable Directive

    The resizable directive works much the same as the draggable directive, it is another jQuery UI based Angular.jsdirective. Here is its code:

    Co llapse | Copy Code

    define(['directives/directives'], function (directives) { directives.directive('resizable', ['$rootScope', function ($rootScope) { return { restrict: 'A', //may need the model to be passed in here so we can apply changes to its left/top positions link: function (scope, element, attrs) {

    element.resizable( { maxHeight: 200, minHeight: 100, //aspectRatio: 16 / 9, stop: function (event, ui) { scope.$apply(function () { scope.updateScale( scope.imageitem.name, { top: ui.position.top, left: ui.position.left }, { width: ui.size.width, height: ui.size.height } ); }); } }); } }; }]);});

    As before since we are changing things (the scale of a UI element) outside the knowledge of the Angular.jscontroller, we need to get the directive to update the controller scope, here is the relevant code:

    Co llapse | Copy Code

    // NOTE: $scope.$apply is called by the resizable directive$scope.updateScale = function (name, pos, size) { var idx = $scope.imageitems.propertyBasedIndexOf('name', name); var foundItem = $scope.imageitems[idx]; foundItem.left = pos.left; foundItem.top = pos.top; foundItem.width = size.width; foundItem.height = size.height;};

    Root Controller

    Some of the internals of the root controller have already been covered, so I will remove the internal code fromthe functions we have already covered, which really just leaves this controller code:

    Co llapse | Copy Code

    define(['controllers/controllers', 'services/liveUpdatesService', 'services/utilitiesService', 'services/imageService', 'services/localStorageService'], function (controllers) { controllers.controller('RootCtrl', ['$window', '$scope', '$location', 'LiveUpdatesService', 'UtilitiesService', 'ImageService', 'LocalStorageService', function ( $window, $scope, $location, LiveUpdatesService, UtilitiesService, ImageService, LocalStorageService) {

    $scope.imageitems = [];

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 10 / 14

  • $scope.imageItemsStorageKey = 'imageItemsKey'; //load existing items from local storage which looks cool, as they show up in their persisted //positions again...Cool if (LocalStorageService.isSupported()) { var currentFavs = LocalStorageService.fetch($scope.imageItemsStorageKey); if (currentFavs != undefined) { currentFavs = JSON.parse(currentFavs); for (var i = 0; i < currentFavs.length; i++) { var favItem = currentFavs[i];

    $scope.imageitems.push(ImageService.createImageItem( favItem.name, favItem.left, favItem.top, favItem.width, favItem.height, true)); } } }

    UtilitiesService.addArrayHelperMethods();

    LiveUpdatesService.eventsStream().subscribe( ..... ..... .....

    );

    $scope.addToFavourites = function (index) { if (!LocalStorageService.isSupported()) { $window.alert('Local storage is not supported by your browser, so saving favourites isn\'t possible'); } else { var currentStoredFavsForAdd = LocalStorageService.fetch($scope.imageItemsStorageKey); if (currentStoredFavsForAdd == undefined) { currentStoredFavsForAdd = []; } else { currentStoredFavsForAdd = JSON.parse(currentStoredFavsForAdd); }

    var scopeImageItem = $scope.imageitems[index]; var favsIdx = currentStoredFavsForAdd.propertyBasedIndexOf('name', scopeImageItem.name); if (favsIdx >= 0) { $window.alert('An item with that name is already in your favourites.'); return; }

    $scope.imageitems[index].isFavourite = true; currentStoredFavsForAdd.push(scopeImageItem); LocalStorageService.save($scope.imageItemsStorageKey, currentStoredFavsForAdd); $window.alert('Saved to favourites'); } };

    $scope.removeFromFavourites = function (index) { if (!LocalStorageService.isSupported()) { $window.alert('Local storage is not supported by your browser, so removing from favourites isn\'t possible'); } else { var currentStoredFavsForRemoval = LocalStorageService.fetch($scope.imageItemsStorageKey); if (currentStoredFavsForRemoval == undefined) { return; } else { currentStoredFavsForRemoval = JSON.parse(currentStoredFavsForRemoval); }

    var scopeImageItem = $scope.imageitems[index];

    var favsIdx = currentStoredFavsForRemoval.propertyBasedIndexOf('name', scopeImageItem.name); $scope.imageitems.splice(index, 1); if (favsIdx >= 0) { currentStoredFavsForRemoval.splice(favsIdx, 1); LocalStorageService.save($scope.imageItemsStorageKey, currentStoredFavsForRemoval); } $window.alert('Item removed from favourites'); } };

    // NOTE: $scope.$apply is called by the draggable directive $scope.updatePosition = function (name, pos) { ..... ..... ..... };

    // NOTE: $scope.$apply is called by the resizable directive $scope.updateScale = function (name, pos, size) { ..... ..... ..... }; }]);});

    It can be seen that most of the root controller's code has already been covered, so what is left to discuss?

    Essentially the code that is left does the the following:

    1. Allows the user to call the addToFavourites function (which will add it to HTML 5 local storage) byusing a button in the image tile UI

    2. Allows the user to call the removeFromFavourites function (which will remove it from the UI and alsofrom HTML 5 local storage) by using a button in the image tile UI

    3. Will read all items and their persisted state from HTML 5 local storage when the page is first rendered,which will cause all the persisted favourite items to appear exactly as they were when the user savedthem to local storage

    Root View

    The view is the easy part, since most of the real work has been done by the various services and the controller.Here is the root view markup:

    Co llapse | Copy Code

    {{imageitem.name}}

  • The Favourites PageThough not as complex as the Root page and its controller the favourites is the 2nd most complicated page, soprobably justifies a bit of an explanation, before we dive head long in to its code.

    So what does this page do exactly?

    The idea is that there will be a set (which could be an empty set) of image data which is stored against a certainkey in HTML 5 local storage. When the favourites view is requested this HTML 5 locally stored data will beexamined, and for all items found a smal thumbnail will be rendered. The user may also click on any of thethumbnails to launch a ColorBox jQuery plugin.

    This is what the favourites page looks like with some items saved within the local storage.

    Click image for larger version

    And this is what it would look like when you have clicked one of the thumnbails

    So how does this page work. Well one of the hard parts was something that you would all probably think was avery trivial thing to do. So in local storage we have a 1 dimensional JSON stringified array, and I wanted to turnthat into a 2 dimensional table layout that I could use with Angular.js ng-repeat binding.

    Favs Controller

    Let's look at the controller first.

    Co llapse | Copy Code

    define(['controllers/controllers', 'services/imageService', 'services/utilitiesService', 'services/localStorageService'], function (controllers) { controllers.controller('FavsCtrl', ['$window', '$scope', 'ImageService', 'UtilitiesService', 'LocalStorageService', function ( $window, $scope, ImageService, UtilitiesService, LocalStorageService) {

    $scope.imageItemsStorageKey = 'imageItemsKey'; $scope.favImageItems = []; $scope.columnCount = 5; $scope.favText = ''; $scope.shouldAlert = false;

    $scope.tableItems = []; while ($scope.tableItems.push([]) < $scope.columnCount);

    if (!LocalStorageService.isSupported()) { $scope.favText = 'Local storage is not supported by your browser, so viewing favourites isn\'t possible'; $scope.shouldAlert = true; } else {

    var currentStoredFavs = LocalStorageService.fetch($scope.imageItemsStorageKey); var currentFavs = []; if (currentStoredFavs != undefined) { currentFavs = JSON.parse(currentStoredFavs); }

    if (currentFavs.length == 0) { $scope.favText = 'There are no favourites stored at the moment'; $scope.shouldAlert = true; } else { var maxRows = Math.ceil(currentFavs.length / $scope.columnCount); $scope.favText = 'These are your currently stored favourites. You can click on the images to see them a bit larger'; if (currentFavs.length < $scope.columnCount) { $scope.tableItems[0] = []; for (var i = 0; i < currentFavs.length; i++) { $scope.tableItems[0].push(ImageService.createFavImageItem(currentFavs[i].name));

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 12 / 14

  • } } else { var originalIndexCounter = 0; for (var r = 0; r < maxRows; r++) { for (var c = 0; c < $scope.columnCount; c++) { if (originalIndexCounter < currentFavs.length) { $scope.tableItems[r][c] = ImageService.createFavImageItem(currentFavs[originalIndexCounter].name); originalIndexCounter++; } } } } } if ($scope.shouldAlert) { UtilitiesService.delayedAlert($scope.favText); } } }]);});

    It can be seen that the bulk of the work here is getting the data from HTML 5 local storage, and translating itfrom a string representation into a JSON 1 dimensional array, and then into a 2 dimenionsal stucture that canbe used to bind against within the markup.

    There are a few other things of note here:

    We use the Angular.js $window rather than "window" to allow the $window service to be replaced by amockWe make use of the LocalStorageService that we saw earlierWe make use of the UtilitiesService that we saw earlierWe make use of the ImageService that we saw earlier

    Favs View

    With all the grunt work done in the controller, the view markup is pretty tiny:

    Co llapse | Copy Code

    Favourites

    {{favText}}

    Notice that neat nested ng-repeat, that is how easy it is to do a table layout in Angular.js once you have thecorrect structure in your scope to iterate over

    ColorBox Directive

    The final piece in the puzzle is how to make these items into a jQuery ColorBox. Knowing what we know now,we should be able to realise that the answer to this lies in the use of yet another directive.

    Yes you guessed it a colorbox directive, which can be seen in the .... anchor tags in themarkup.

    Here is the colorbox directives code, where you can see that this is restricted to attribute usage, and simplydelegates the work to the actual jQuery ColorBox (which was referenced as a requirement within the Require.jsconfiguration, so we know its loaded ok, otherwise the Angular.js would not have started)

    Co llapse | Copy Code

    define(['directives/directives'], function (directives) { directives.directive('colorbox', ['$rootScope', function ($rootScope) { return { restrict: 'A', //may need the model to be passed in here so we can apply changes to its left/top positions link: function (scope, element, attrs) { $(element).colorbox({ rel: 'group3', transition: "elastic", width: "50%", height: "50%" }); } }; }]);});

    The About PageThe about page is just static text, so nothing groovy here really. I added this page just so there was enoughroutes in the demo app to make it more full featured I suppose. For completeness here is the screen shots ofwhat the about page looks like

    "

    Click image for larger version

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 13 / 14

  • Permalin k | Advertise | Privacy | Mob ile W eb03 | 2.7.131126.1 | Last U pdated 5 Sep 2013

    Article Copyrigh t 2013 by Sach a B arberEveryth in g else Copyrigh t CodePro ject, 1999-2013

    Terms o f U se

    Layou t: f ixed | f lu id

    Sacha BarberSoftware Developer (Senior) United Kingdom

    I currently hold the following qualifications (amongst others, I also studied Music Technology andElectronics, for my sins) - MSc (Passed with distinctions), in Information Technology for E-Commerce- BSc Hons (1st class) in Computer Science & Artificial Intelligence Both of these at Sussex University UK. Award(s)

    I am lucky enough to have won a few awards for Zany Crazy code articles over the years

    Microsoft C# MVP 2013Codeproject MVP 2013Microsoft C# MVP 2012Codeproject MVP 2012Microsoft C# MVP 2011Codeproject MVP 2011Microsoft C# MVP 2010Codeproject MVP 2010Microsoft C# MVP 2009Codeproject MVP 2009Microsoft C# MVP 2008Codeproject MVP 2008And numerous codeproject awards which you can see over at my blog

    Add a Comment or Question Search this forum Go

    That's ItAnyway that is all I wanted to say for now, I hope you have enjoyed this article and got something out of it. Iknow I did personally. It was a tricky one to write in a lot of ways as it had a few new concepts for me, I amhowever pretty pleased with the end result. If you like what you have read/seen, and feel inclined to leave avote/comment that would be cool.

    Anyway bye bye until the next one, which hopefully will not be as long in coming as this one was.

    LicenseThis article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author

    Article Top

    Comments and Discussions

    Profile popups Spacing Relaxed Noise Very High Layout Normal Per page 10

    Update

    First Prev Next

    Veronica Blanco 16-Nov-13 10:16

    S. M. Ahasan Habib 5-Nov-13 11:50

    M Rayhan 27-Oct-13 3:41

    Bernardo Castilho 6-Sep-13 11:22

    Sacha Barber 6-Sep-13 11:29

    saxenaabhi6 5-Sep-13 20:29

    Sacha Barber 6-Sep-13 3:34

    Marcelo Ricardo deOliveira

    5-Sep-13 17:44

    Sacha Barber 6-Sep-13 3:33

    thangskyline 2-Sep-13 3:53

    Last Visit: 31-Dec-99 23:00 Last Update: 29-Nov-13 2:02 Refresh 1 2 3 4 5 Next

    General News Suggestion Question Bug Answer Joke Rant Admin

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    I have a pair of questions, separate the model objects

    My vote of 5

    My vote of 5

    My vote of 5 [modified]

    Re: My vote of 5

    My vote of 5

    Re: My vote of 5

    My vote of 5

    Re: My vote of 5

    Cannot download the source code

    Angular.js example application - CodeProject 29-11-2013

    http://www.codeproject.com/Articles/637430/Angular-js-example-application 14 / 14

    Angular.js example applicationTable Of ContentsIntroductionThe Demo App OverviewAngular.Js IntroductionAppsServicesModulesDependency InjectionRoutingViewsControllersScopeDirectives

    The PublisherThe Angular.js WebsiteRequire.js UsageThe Main App SetupThe RoutingThe Root PageLiveUpdatesServiceLocalStorageServiceImageServiceUtilitiesServiceDraggable DirectiveResizable DirectiveRoot ControllerRoot View

    The Favourites PageFavs ControllerFavs ViewColorBox Directive

    The About Page

    That's ItLicenseAbout the AuthorComments and Discussions