Bit of Technology

  • Archive
  • About Me
    • Advertise
    • Disclaimer
  • Speaking
  • Contact

Building SPA using AngularJS – Part 3

January 13, 2014 By Taiseer Joudeh 40 Comments

Be Sociable, Share!

  • Tweet
  • Email
  • WhatsApp

This is the third part of Building SPA using AngularJS Series. The topics we’ll cover are:

  • Building SPA using AngularJS – Part 1
  • Building SPA using AngularJS – Part 2
  • Building SPA using AngularJS – Part 3 (This Post)

Update (2014-May-5) New post which covers adding GulpJS as Task Runner for our AngularJS application:

  • AngularJS with touch of GulpJS

Update (2014-June-1) New post which covers Implementing AngularJS Token Authentication using ASP.NET Web API 2 and Owin middleware:

  • Token Based Authentication using ASP.NET Web API 2, Owin, and Identity

Building SPA using AngularJS – Part 3

In this post we’ll implement the last feature in our application where we’ll allow end users to bookmark their favorite places for future visits, so we need permanent repository to save this information. We’ll build our RESTful data service using Asp.Net Web API (any back end technology can be used to create this service, so if you are not familiar with Web API you can use another technology to build a service layer). To keep things simple we’ll save the bookmarked places information along with the username, so we’ll have single database table as the image below:

DBTable

The end user will be asked to enter username in order to start bookmarking places, if there is available user in the context she can bookmark as many favorite places as she wants without asking for username. Username modal view will look like the below:

usernameView

To view the saved bookmarked places which user has added, she can click on My Places menu on “index.html” page and a new view will be displayed containing list of all bookmarked places. View will be as the below:

BookmarkedPlaces

So let’s start implementing those features.

Step 1: Building the RESTful service layer:

We’ll be using Entity Framework “Code First approach” to build our database, all this code is implemented in separate data access layer named “FoursquareAngularJS.Data”, I won’t dig into how to create the database model or use the factory pattern as I’ve blogged about them earlier, you can check this post for building the database model, and this post for creating the repository pattern. All you need to run this application locally is to have instance of SQLExpress or LocalDB, just configure the connection string and the database will be created automatically.

Our “FoursquareAngularJS.Web” project is configured to use Web API, we need to create two Web API Controllers one for Saving/Retrieving bookmarked places, and the other for checking if the username already exists in the database, I’ll not cover how we can configure Web API routes, you can check my previous post to follow along. You can view source code of “PlacesController” here, for “UsersController” here, and “WebApiConfig” class here.

To check the JSON response format for the the method responsible to return bookmarked places for user, we can issue HTTP Get request to the URL: http://explore4sq.azurewebsites.net/api/places/taiseerj note that “taiseerj” will be replaced by the username in our app.

Step 2: Adding service to communicate with our RESTful service:

Now we need to add new Angular service which is responsible to communicate with our RESTful service, so let’s add new file named “placesDataService.js” under “app–>services”, Now open the file and paste the code below :

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
'use strict';
app.factory('placesDataService', function ($http, toaster) {
 
    var serviceBase = '/api/places/';
    var placesDataFactory = {};
    var userInContext = null;
 
    var _getUserInCtx = function () {
        return userInContext;
    };
 
    var _setUserInCtx = function (userInCtx) {
        userInContext = userInCtx;
    };
 
    var _savePlace = function (venue) {
        //process venue to take needed properties
 
        var miniVenue = {
            userName: userInContext,
            venueID: venue.id,
            venueName: venue.name,
            address: venue.location.address,
            category: venue.categories[0].shortName,
            rating: venue.rating
        };
 
        return $http.post(serviceBase, miniVenue).then(
 
        function (results) {
            toaster.pop('success', "Bookmarked Successfully", "Place saved to your bookmark!");
        },
        function (results) {
            if (results.status == 304) {
                toaster.pop('note', "Already Bookmarked", "Already bookmarked for user: " + miniVenue.userName);
            }
            else {
                toaster.pop('error', "Faield to Bookmark", "Something went wrong while saving :-(");
            }
            return results;
        });
    };
 
    var _getUserPlaces = function (userName, pageIndex, pageSize) {
 
        return $http.get(serviceBase + userName, { params: { page: pageIndex, pageSize: pageSize } }).then(function (results) {
            return results;
        });
    };
 
    var _userExists = function (userName) {
        return $http.get("/api/users/" + userName).then(function (results) {
            return results.data;
        });
    };
 
    placesDataFactory.getUserInContext = _getUserInCtx;
    placesDataFactory.setUserInContext = _setUserInCtx;
    placesDataFactory.getUserPlaces = _getUserPlaces;
    placesDataFactory.userExists = _userExists;
    placesDataFactory.savePlace = _savePlace;
 
    return placesDataFactory
});

So basically what we’ve implemented in this factory is the below:

  • We’ve used the built-in Angular service $http instead of $resource, we can use the $resource as well, but I prefer to use $http to show you how we can implement both, there is no dependencies once you inject $http, so we can inject on any service directly.
  • We’ve injected toaster third party service which is JavaScript non blocking notification service, this service will be used to display notification for end user once she bookmark a place. You can check how to configure this service here.
  • As we mentioned before, Angular services are singleton objects, they live in the entire application, so we’ve defined variable named userInContext in this service, we’ll depend on this variable to decide if there is a user to bookmark places or not, Note: this is very naive implementation and should not be used in real world application, I’ve used it here to keep things simple in the demo. If you hit F5 and refreshed the shell page, this variable will be flushed.
  • We’ve added function named savePlace which is responsible to issue HTTP Post request to our RESTful API, the request payload body will contain JSON object matches the data model we defined in our API.
  • We’re using .then promise to manipulate and access the returned response directly in the service, so if the response is 200 OK we are displaying success notification message, if the response is not 200 OK, for example 304 Not modified, then we are returning a notification that place already bookmarked for this user. Note: displaying a notification on the service level is not the right place to do, we should do this in controller, but I preferred to put it here because we’re going to call the save function from two different controllers and we want to display the same notification on both controllers, this falls more into sharing code.
  • We’ve implemented a function which retrieves a list of bookmarked places for specific user as well another function to check if the username has been used before.

Step 3: Implementing bookmark places feature

Now we’ll get back to the controller “placesExplorerController” and inject the newly created service “placesDataService” then add new function named “bookmarkPlace()” as the code below:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$scope.bookmarkPlace = function (venue) {
 
    if (!placesDataService.getUserInContext()) {
 
        var modalInstance = $modal.open({
            templateUrl: 'app/views/userprofile.html',
            controller: 'userContextController',
            resolve: {
                venue: function () {
                    return venue;
                }
            }
        });
    }
    else {
        placesDataService.savePlace(venue).then(
        function (results) {
            // Do nothing as toaster showing from service
        },
        function (results) {
            // Do nothing as toaster showing from service
        });
    }
 
};

This function checks if the variable named “userInContext” in service “placesDataService” is not null, if this is the case, then we save the place directly by calling placesDataService.savePlace(venue), if it is null, then we’ll display new modal named “userProfile.html” for the user asking her to provide a username, this modal has new controller named “userContextController”. Showing the modal is identical to what we did with the modal used to display places photos, you can check the view source html here, and the controller source code here.

Step 4: Implementing My Places Feature

This is last feature in our application, where the user can view all bookmarked places, to implement it we need to add a new controller named “myPlacesController”, so add new JS file “myPlacesController.js” under “app–>controllers”, open the file and paste the code below:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
'use strict';
app.controller('myPlacesController', function ($scope, placesDataService) {
 
    $scope.myPlaces = [];
 
    //paging
    $scope.totalRecordsCount = 0;
    $scope.pageSize = 10;
    $scope.currentPage = 1;
 
    init();
 
    function init() {
        getUserPlaces();
    }
 
    function getUserPlaces() {
 
        var userInCtx = placesDataService.getUserInContext();
 
        if (userInCtx) {
 
            placesDataService.getUserPlaces(userInCtx, $scope.currentPage - 1, $scope.pageSize).then(function (results) {
 
                $scope.myPlaces = results.data;
 
                var paginationHeader = angular.fromJson(results.headers("x-pagination"));
 
                $scope.totalRecordsCount = paginationHeader.TotalCount;
 
            }, function (error) {
                alert(error.message);
            });
        }
    }
 
    $scope.pageChanged = function (page) {
 
        $scope.currentPage = page;
        getUserPlaces();
 
    };
 
});

What we’ve implemented here is simple, we’ve just injected the “placesDataService” so we’ll be able to load user saved places if there is username in the variable “userInContext” by calling method “getUserPlaces”, then we fill the returned data into myPlaces model.

Now we need to add new view named “myplaces.html” to work with this controller, the source code for this view can be found here, Do not forget to configure $routeProvider so Angular will be aware that the view “myplaces.html” is mapped to the controller “myPlacesController” when the user request the URL “/places”, this code should be added in app.js file as the code below:

JavaScript
1
2
3
4
5
6
7
8
app.config(function ($routeProvider) {
 
    $routeProvider.when("/places", {
        controller: "myPlacesController",
        templateUrl: "/app/views/myplaces.html"
    });
 
});

That’s all for now!

I hope you liked this tutorial, I tried my best to explain all important parts of this application during this tutorial, you can always get back to the complete running source code on github, or try the application using the live demo.

Please feel free to drop any comment or suggestion to enhance this application.

Be Sociable, Share!

  • Tweet
  • Email
  • WhatsApp

Related Posts

  • AngularJS Authentication Using Azure Active Directory Authentication Library (ADAL)
  • Getting started with ASP.NET 5 MVC 6 Web API & Entity Framework 7
  • Two Factor Authentication in ASP.NET Web API & AngularJS using Google Authenticator
  • Decouple OWIN Authorization Server from Resource Server
  • ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app

Filed Under: AngularJS, Javascript, Single Page Applications Tagged With: AngularJS, Foursquare API, Single Page Applications, SPA, Web API

Comments

  1. johnny says

    January 17, 2014 at 12:42 pm

    woo…. amazing AngularJS, anyway thanks for the tutorial i really learnt alot from your tutorial that cleared my knowledge in line with AngularJS thanx ….

    Reply
    • tjoudeh says

      January 17, 2014 at 12:45 pm

      You welcome Johny, glad you liked the tutorial. Good luck in learning AngularJS.

      Reply
  2. josh says

    January 17, 2014 at 1:38 pm

    Hi i have a problem when run my project it always show
    “Webpage Error”
    Error: ‘app’ is undefined,
    But its already defined as a global variable in the app.js script please HELP OUT!!

    Reply
    • tjoudeh says

      January 17, 2014 at 1:44 pm

      Hi Josh, did you reference your app.js file in index.html page, as well the order of JS files reference is important, this needs to be on top before any controller or service? Please fork my rgithub repo and compare the order of JS files reference.

      Reply
  3. zevs7772006 says

    January 20, 2014 at 1:51 am

    Please, make an example using eTags.

    Reply
    • tjoudeh says

      January 20, 2014 at 7:14 am

      I will soon, most probably next week.

      Reply
      • Rakoczi Markus says

        February 5, 2014 at 2:03 am

        Awesome tuts, waiting for eTags me too. Thanks.

        Reply
        • tjoudeh says

          February 5, 2014 at 10:47 am

          Thank you, working on the API cashing post.

          Reply
        • Taiseer Joudeh says

          February 18, 2014 at 4:48 pm

          Hello Rokoczi,

          I’ve posted part 11 of web api tutorial covering caching and using eTags.

          Reply
  4. mediakid (@mediakid) says

    February 5, 2014 at 10:44 am

    Awesome! Comprehensive and clear! I must say thanks to you tjoudeh.
    This is the best tutorial I have seen so far after i have digged for 2 weeks to find learning materials. (yes, even better than official one, no kidding 🙂 )

    Reply
    • tjoudeh says

      February 5, 2014 at 10:46 am

      appreciate it, glad that was very useful for your learning purposes 🙂 keep tuned as I’m planing to build another tutorial using angular, phone gap, windows azure mobile services, kind of end to end application.

      Reply
      • Rafael Merlin says

        January 23, 2015 at 9:23 pm

        Please do that! This would be amazing! Specially the phone gap (or cordova) integration =-D. This tutorial was excellent, I’ve learned a lot by using it. Thanks a ton!

        Reply
        • Taiseer Joudeh says

          January 24, 2015 at 1:02 am

          You are welcome, I will do my best to implement it 🙂 thanks for your comment.

          Reply
  5. Jesper Ordrup (@jesperordrup) says

    February 6, 2014 at 7:22 pm

    I like that your service also holds the code for handling the request. I think it belongs here and not in the controller. But you allow the service to respond with toaster popups. it seems wrong to let the service control any viewable feedback.

    It should be left to the controller to act on the data, right?

    Best
    Jesper

    Reply
    • tjoudeh says

      February 6, 2014 at 7:27 pm

      Hello Jesper,

      Thanks for your feedback, you are absolutely right, as well I’ve mentioned that it is not the right implementation to control UI behavior in the service as quoted here:”displaying a notification on the service level is not the right place to do, we should do this in controller, but I preferred to put it here because we’re going to call the save function from two different controllers and we want to display the same notification on both controllers, this falls more into sharing code.”

      Reply
  6. Jesper Ordrup (@jesperordrup) says

    February 6, 2014 at 7:24 pm

    Great series of posts btw.

    Reply
    • tjoudeh says

      February 6, 2014 at 7:28 pm

      Thank you Jesper, glad you like them 🙂

      Reply
  7. Mac Osx On Pc says

    February 8, 2014 at 1:18 pm

    It’s awesome to visit this site and reading the views of all friends concerning this post, while I
    am also zealous of getting experience.

    Reply
  8. Rodrigo says

    February 12, 2014 at 1:28 am

    nice.
    how you implement authorization and access level?

    Reply
    • tjoudeh says

      February 15, 2014 at 12:24 am

      Hello Rodrigo,

      I’ll send you soon a sample project I worked on which covers authentication, what is the back-end you are using?

      Reply
      • Rodrigo says

        February 15, 2014 at 2:13 am

        Hi tjoudeh
        I’m use Asp.net MVC4

        Send in my email please

        Thanks

        Reply
        • Taiseer Joudeh says

          February 19, 2014 at 4:36 pm

          Check your inbox now.

          Reply
          • Migu says

            March 10, 2014 at 3:15 pm

            I’m also interested about authentication part, I’m using Web API 2. Can you send me? Thanks.

          • Taiseer Joudeh says

            March 11, 2014 at 2:05 pm

            Hello Migu, I’ll soon

  9. TramTri says

    April 14, 2014 at 6:22 pm

    Thank you so much for your helpful articles. It’s helping me so much in learning AngularJS from a novice user. Thanks again and keep up your good works.

    Reply
    • Taiseer Joudeh says

      April 15, 2014 at 12:26 am

      You are welcome TramTi, glad you like it!

      Reply
  10. ammy grewal says

    May 12, 2014 at 4:37 pm

    Hello Taiseer Joudeh,

    Thank you so much.Its really awesome tutorial,I learn a lot from this and waiting for your next article.

    Reply
    • Taiseer Joudeh says

      May 12, 2014 at 4:43 pm

      Hello Ammy,

      Glad you liked this tutorial, currently I’m working on nice another tutorial using AngularJS for building Hybrid Mobile apps, so keep tuned!

      Reply
      • ammy grewal says

        May 13, 2014 at 8:16 am

        I am using ASP.Net MVC4, could you please send me authentication code.

        Reply
  11. lokeshsp says

    June 22, 2014 at 9:23 pm

    I like the way you deliver the toturial step by step and making necessary points what to look out for and reference injection. Great post to learn Angular. The best one on spa with angular andwebapi till now !

    Reply
    • Taiseer Joudeh says

      June 23, 2014 at 12:20 am

      Thank you lokeshsp for your nice comments, glad it was helpful to learn from 🙂 subscribe to my blog to keep tuned as I’m working on another tutorial covering Hybrid mobile app solution.

      Reply
  12. Shaban Lukyamuzi says

    July 12, 2014 at 5:28 pm

    This is amazing!!!,i feel like an angularjs guru

    Reply
    • Taiseer Joudeh says

      July 14, 2014 at 10:31 am

      Glad you like it AngularJS Guru 🙂

      Reply
  13. Aram Tchekrekjian says

    October 9, 2014 at 12:32 pm

    Thanks Taiseer for a comprehensive, cohesive and informative step by step AngularJS tutorial.

    Reply
    • Taiseer Joudeh says

      October 9, 2014 at 12:34 pm

      Most welcome Aram, glad you liked it 🙂

      Reply
  14. Hoàng Lê says

    August 12, 2015 at 10:34 am

    Wow excellent, I learnt a lot from yours tuts, You are my lifesaver. Thanks a lot.

    Reply
    • Taiseer Joudeh says

      August 15, 2015 at 1:16 am

      You are most welcome, glad that posts were useful

      Reply
  15. Leszek says

    January 14, 2016 at 2:33 pm

    Great post. Thank you.

    Reply
    • Taiseer Joudeh says

      January 17, 2016 at 11:26 am

      You are welcome, happy to help.

      Reply
  16. Karmesh says

    October 17, 2016 at 10:46 pm

    how it’s adding…?
    i didn’t fount….

    value=”{{!ctrl.user.id ? ‘Add’ : ‘Update’}}”

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About Taiseer

Husband, Father, Consultant @ MSFT, Life Time Learner... Read More…

Buy me a coffeeBuy me a coffee

Recent Posts

  • Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3
  • Secure ASP.NET Web API 2 using Azure AD B2C – Part 2
  • Azure Active Directory B2C Overview and Policies Management – Part 1
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4

Blog Archives

Recent Posts

  • Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3
  • Secure ASP.NET Web API 2 using Azure AD B2C – Part 2
  • Azure Active Directory B2C Overview and Policies Management – Part 1
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4

Tags

AJAX AngularJS API API Versioning ASP.NET Authentication Autherization Server Azure Active Directory B2C Azure AD B2C basic authentication C# CacheCow Client Side Templating Code First Dependency Injection Entity Framework ETag Foursquare API HTTP Caching HTTP Verbs IMDB API IoC Javascript jQuery JSON JSON Web Tokens JWT Model Factory Ninject OAuth OData Pagination Resources Association Resource Server REST RESTful Single Page Applications SPA Token Authentication Tutorial Web API Web API 2 Web API Security Web Service wordpress.com

Search

Copyright © 2022 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in

loading Cancel
Post was not sent - check your email addresses!
Email check failed, please try again
Sorry, your blog cannot share posts by email.