Learning AngularJS–Part 4

Sorry, it has been a while since my last post. 

To finish off the first series of my AngularJS posts, I would like to talk about how I went about updating an existing person and a few other things that I have not covered up to now.

For those who have not read the previous posts you can reach them here The Beginning ,Part 2, and Part 3

Like adding a new person to our personnel record, the application will use the routing engine to determine where to go (“#” represents the routing engine) so our route this time is #/updatePerson.  The route can then work out what controller and partial to use for updating.

Our route provider should look like this:

$routeProvider.when("/updatePerson/:id", {        

controller: "singlePeopleController",        

templateUrl: "/templates/updatePerson.html",   

});

The “:id” part of the url allows the id of the person to be set.  I’ve kept this in the one file but it might be better to split these up into multiple files, my intention is to do that.

The singlePeopleController then retrieves the person using the data service which I created to avoid writing the same code over and over again.  So the first action is to retrieve the person using the id that you have passed in.  I originally retrieved the person by accessing an person object stored in memory instead of using the api to go back to the database but I found that the update was going wrong.  The details were not getting updated, the application would overwrite the new details with the old details.  It was like the save was not happening at all.

After returning the right person, I proceeded with the update.  The person was added to a $scope.Person.  I passed the $scope.person to the updatePerson data service method.  This posted the data to the api and in turn saved it to the database.  If it was successful, it would return it the beginning using $window.location = “/#”. 

var _updatePerson = function (existingPerson) {         var deferred = $q.defer();         $http.put("/api/People", existingPerson)             .then(function (result) {                 var updatedPerson = result.data;                 _people.splice(0, 0, updatedPerson);                 deferred.resolve(updatedPerson);             },             function () {                 deferred.reject();             });         return deferred.promise;     };
function singlePeopleController($scope, dataService, $window, $routeParams, $log) {     $scope.person = null;     $scope.$log = $log;     //$log.log("Id : " + $routeParams.id);     dataService.getPerson($routeParams.id)         .then(function (person) {             // Success             $scope.person = person;             $log.log("Person : " + person.Salutation);         },         function () {             alert("Cannot find person");             //$log.log("Cannot find person");             $window.location = "/#";         });     $scope.update = function () {         dataService.updatePerson($scope.person)             .then(function () {                 $window.location = "/#";             },             function () {                 alert("Cannot update person");             });     };
}

Instead of save() this time I use update().  Update is $scope.update a function which the form uses when the submit is called. i.e. clicking the update button.

One of the issues that I did have to solve was how to put the updated salary into the salary list for that person.  I wanted to search for that person and show the historical salaries for the personnel. 

person.Salary[0].Salary

I’m still not 100% sure if that is correct way of doing this but it works for now.  I went to the forums asking in the Angular JS forum, a couple of people had replied saying that this was a good way to access the list and update it.  I still need to do a bit work on bringing the updated value.

What I still have left to do is implement a search which allows user to search for a person and it would details of their salaries and I would like to add some testing around AngularJS with the ones that I played with is Jasmine / Karma.  That’s because they are on the AngularJS site.

The only other function that I have in the data service is FindPerson, it loops around the people object stored in memory and return the found one if the id of the person matches. 

function _findPerson(id) {         var found = null;         $.each(_people, function (i, item) {             if (item.Id == id) {                 found = item;                 return false;             }         });         return found;     }

Another thing completely off topic and I can’t get right is how to properly format code in blog post.  The formatting seems to go totally awry.  Anyone who knows can contact me please.

I promise I won’t leave it so long next time…my plan is to regularly update this blog so that my technical writing, communication and blog posts improve.

Learning AngularJS – Part 3

Following on from my previous posts about AngularJS Learning AngularJS – The beginning and Learning AngularJS – Part 2. I would like to talk a bit about the form to add a person to my personnel application. My trials on how it went plus what I learnt along the way.

First of all, returning to the main page of the application. The page will always have a button to add a record and when the records are added, there will be a button to amend those records. So what happens when you click the add button. Soon as you hit the main page, the application makes use of the routing engine “#”, so that the application knows where to go, we add another entry into the module config saying that when #/addperson is called, use this controller and go to this template (sometimes called a partial). Example:

$routeProvider.when("/addNewPerson", {
controller: "newPeopleController",
templateUrl: "/templates/addNewPerson.html",
});

The addPerson.html is then injected into data-ng-view on the index.cshtml page.

The add person page is made slightly easier by the fact that I didn’t need to populate the form with data. However, a function to add a person is still needed in your service or factory (it is probably worth pointing out that although I used the terms there, my data service uses factory, confused?? Any examples that I seen have used factory when defining a service and most people can’t give you an answer when questioning the differencing between the two terms).

var _addPerson = function (newPerson) {
var deferred = $q.defer();


$http.post("/api/People", newPerson)
.then(function (result) {
var newlyCreatedPerson = result.data;
_people.splice(0, 0, newlyCreatedPerson);
deferred.resolve(newlyCreatedPerson);
},
function() {
deferred.reject();
});


return deferred.promise;
};

This function will go to the post method of the WebAPI people controller and save the input entered to the database. It uses a promise to return data to the controller, the promise is accessed through the deferred API in AngularJS. The resolve indicates a successful outcome and reject, an error or something isn’t right, and promise wraps it up and passes it back. In the dataservice, we can’t have bespoke controller functionality like error messages or redirecting to specific addresses. The promise allows the code to pass back the outcome to controller and the controller can do the details. It is probably worth pointing out that although I’ve used .then to define the outcome of my promises newer versions of AngularJS can use .success and .error. The final thing on the addPerson function is that splice will add the record into the personnel list without having to call the WebAPI get method again and the position specified.

The dataservice will have a public part to it in the return { addPerson = _addPerson }. The addPerson can be accessed in controllers, something like dataservice.addPerson so you don’t need to duplicate code. Good, right?

Hopefully now this should be making sense. The controller code is as follows:

function newPeopleController($scope, $http, $window, dataService)
{
$scope.newPerson = {};
$scope.salary = {};


$scope.save = function () {
dataService.addPerson($scope.newPerson)
.then(function () {
$window.location = "/#";
},
function() {
alert("Cannot save person");
});
};

The save() function is called in the html template by using ng-submit on the form tag . The data- bit is ro stop the editor complaining about the syntax.

In the HTML itself, there is couple of nice wee things. For example, I take advantage of the HTML5 required and placeholder attributes plus use ng-class=”{‘has-error’: AddNewPerson.salutation.$error.required}”. This will highlight the outline of the textbox in red if there is no text in a required field and then remove it as you type. Following on from that, I included the ng-disabled=”AddNewPerson.$invalid” tag so that the save button is disabled until all invalid data is removed. In addition, I use the ng-model attribute (ng-model=”newPerson.surname”) to gather up the data to post to the WebAPI method. Simple things but all good stuff.

Coupled with Bootstrap 3.0 to style the application it is all fairly lightweight and easy to learn so far.

Problems

In the first post I spoke about a problem relating to adding a person with an address but it was really the way that I was using the data and Automapper.

I think going forward the way that salary is entered has to change. The domain property is a list and I struggled to get the data into the list. Eventually I used an individual salary amount property and used Automapper to map it correctly. I may try to do this differently by changing the page to either use a table for salary and add to it or break the pages up to add person details first then salary. That’s a brief insight into my thinking now. Any thoughts welcome?

Until next time…

Learning AngularJS – Part 2

As part of the series of posts that I’m planning to write about learning AngularJS, I’m going to write about each piece of significant functionality in the application.  I provided a brief explanation of the application in Learning AngularJS – The beginning.  In this post, I’m going to detail the search feature, explaining the way that I want it to work and what the problems that I encountered were.

I had decided early on that I wanted to place a search box and button on the header of each of my pages, mainly because of ease of use.  Partly because I wanted the user to be able to search from any point in the application.  I had originally looked at the Bootstrap Typeahead Component but keeping with the AngularJS theme, my next stop was Angular UI Bootstrap.  I had previously looked at these components for the work project that I was on.

In the module, I defined

var module = angular.module("mainIndex", ['ui.bootstrap']);

Specifying ui.bootstrap in the square brackets as part of the module declaration allows the Angular UI Bootstrap to be used,

The code to use the typeahead on the Index.cshtml is:

<div data-ng-controller="SearchController">
     <div class="form-group">
     <input type="text" 
               typeahead-on-select="setPerson($item.Id)"
               data-ng-model="selected" 
               placeholder="Personal Records" 
               typeahead="person as person.FirstName + ' ' + person.Surname for person in getPersonalRecords($viewValue) | filter:$viewValue"                                  typeahead-loading="loadingRecords" class="form-control">                                 
                 </div>                                                                                                                                                    <button class="btn btn-default" data-ng click="search()">Search</button>          
                 </div>

On the first div, there is a attribute value with the controller name defined.  I’m not sure whether I strictly need this as at the top of the index.cshtml page, I have an attribute, which tells me the AngularJS module to use.  The attribute is ng-controller but by adding “data-” you can stop the editor thinking ng-controller is a problem. By defining “data-“, the editor is tricked into thinking that this is a custom attribute.

The typeahead-on-select attribute allows the id of the person selected to be sent back to the controller.  The attribute data-ng-model should have performed this function too but I could not get the variable selected to pass a value across even with the $scope object injecting it.  The typeahead attribute specifies what the user will see like first name and surname and also called the function within the controller code to take what has been entered into the search box and contact the web api get method to return people.  The typeahead loading attribute will display the text or image specified.  The image up to now always goes slightly wrong for me.  That’s how I stuck with text.  Finally, I have a search button to take my selection and display it on a search results page.

Problems:

When I first added the typeahead input box I couldn’t get the person list to display at all.  This turned out be a flaw in the way that I returned the data to the page.  I was trying to add the data to $scope.person variable thinking that it would bind it and I could use person on the index page.  All that was needed was return result.data and the person list would display correctly.

My other issue was that when the user clicked search, the selected values were not be passed across.  The examples and posts were all favouring ng-model selected.  selected would then bind back to the controller providing it was specified.  I could never get this to work instead using typeahead-on-select, which used a function within the controller to pass back the value and assign it to variable.  Exactly the same way ng-model would but with more code.

The AngularJS controller itself is:

function SearchController($scope, $http, $log, $window) {

$scope.selected = '';
$scope.personal = [];
$scope.$log = $log;

$scope.getPersonalRecords = function (val) {
return $http.get('/api/People', {
params: {
searchTerm: val
}
}).then(function (res) {
return res.data;
});
};

$scope.setPerson = function (person) {
$scope.selectedPerson = person;
};

$scope.search = function () {
$log.log("Selected: " + $scope.selectedPerson)

$window.location = "Main#/searchPerson/" + $scope.selectedPerson;
}

The four parameters that are injected into the controller are $scope, which helps with the two way data binding, $http, which allows me to call the web api methods via a callback, $log, which is useful for outputting value and debugging through the code, and $window, which allows the controller to navigate away from the current view.

The first function gets the personal records using web api based on a search term that is entered by the user. For some reason, I have chosen to use a $http shortcut instead of using a data service that I have defined. I will speak more about the data service in later posts but that should change to dataService.getPeople(…) instead of $http.get(…).  When injecting the dataService into the controller the dollar ($) sign is not needed. The web api method will then return the result enabling the data to rendered on the page.

The second function setPerson is used to capture the id of the person selected after the search so that can be passed back to the search function further down. Opted for this way because I struggled to get ng-model to pass the value on its own. The input tag typeahead-on-select will then call the function, which sets selectedPerson variable.

The third function search takes the selected value and uses it to redirect the user to a search page.

I think that just about covers the basics of what I did. If there is anything that I’ve left out or could be done better, please do not hesitate to leave a message. Also sorry about the code examples formatting, just getting used to wordpress.

Learning AngularJS – The beginning

Hi, first post.

A few months back I got an opportunity to use AngularJS on a project in work.  Unfortunately, the AngularJS bits got pulled before the end of the first sprint but this was enough to peak my interest and motivate me to build a simple application using AngularJS.  This post and subsequent posts will chart my progress and pain during this journey of discovery on my own project.

Let’s go back to the beginning, my journey started at work, part of the learning curve was to go onto Pluralsight and complete a course.  The course was by Shaun Wildermuth around Bootstrap, MVC and AngularJS.   Coupled with the extensive documentation for AngularJS and what seems to me as a big push by Google to drive AngularJS forward, there was a lot of examples and people using it.

I started by taking an old existing MVC application, which I generally use for experimentation and added AngularJS to it.  This used Entity Framework 6.0, AutoFac, Automapper, MVC 4, NUnit, and Rhino Mocks.  Later I added Web API and I hope to talk about that in blogs later.

Brief Summary of Application

The application is a small fake personal management system, which allows the user to log in, view, search, and and update personal records for a company.

After logging into the application, the user will be presented with an index page with the company employees’ on it.  It serves as a main navigation place for the rest of the application.

In the module, I set up a routeProvider to look at a url and go to my given AngularJS controller, which will use a partial view html template to render the display.

$routeProvider.when("/", {
controller: "peopleController",
templateUrl: "/templates/peopleView.html",
});

To get the data, I use a very simple WebAPI controller to get people, get a person, add a person and update a person.  The two way data-binding in the templates, which AngularJS provides is great, essentially {{ Person.FirstName }} is enough to render and persist the data back to the Web API controller and ending up in the database.

Inside the index view, I have a ViewData.InitModule property which tells the application which modules that I want to use. There is also this line data-ng-view which allows me to inject the partial view html template into the page

Right now, I’ve put all my controllers, modules and services within the one main-index.js.  Later on, I’ll split out the modules and services into separate files.  I’ve looked at angular seed and once I get more confident with the syntax I’ll use this to structure the project correctly.

In later blogs, I will try and talk about each part individually, but that provides enough detail for now.  Just now, I want to talk about some issues that I had.

First problem

I had used the aspx view engine and try as I might, I was unable to get the routing engine in AngularJS to work using this view engine.  All the examples and posts were all using the Razor view engine.  So after several nights of trying I converted all the pages in the solution to Razor.  I still don’t know if it is possible and it will something that I will try again once I become more familiar with AngularJS.  The point that I thought enough was enough was when I tried to give the page the AnguarJS module name so that I could use the routing engine to direct the controller to all the partial page templates and nothing happened.  I think the page was treating the name of the module as just text to be added to the page rather than text that could be a name of module.  Hence it would not see the controllers on the page and nothing would work.  I was getting a blank page.

Second problem

When it came to adding a new person into my application, one of the properties was Address Line 1.  This property was stored within an Address object.  I could see that  Address Line 1 was not getting populated from the page.  Initially I tried Person.Address[0].AddressLine1, this is wrong, the reason that this doesn’t work is that Address is not an array.  In AngularJS, you will access such a property as follows as Person.Address['AddressLine1'].  The actual problem with the Address Line 1 was that the object that I was querying for Address Line 1 didn’t contain the data.  Once I corrected the query, everything was okay.  Lesson Learned!

Third problem

I had a salary collection in my person object.  This was so that I could return a history of a person’s salary.  The problem was that I had to add a single salary to the collection every time I added or updated the personal record.  This time though, I could access salary like an array Person.Salary[0].Amount.  The problem was that the data sent to the method within the web api controller wasn’t mapping the salary in the person object.  In the end, I solved this problem with automapper mapping the salary to a new list object which I would create when doing the mapping.  I could not find a solution to make the salary map through pure AngularJS.  I did try to work a solution to the problem with ng-repeat and ng-model but the problem still existed or the application would output how many salaries I had stored.

These are the main silly issues I have encountered.  There will be better ways to solve these issues but at this current time this is way that I solved them.

The application itself is ongoing and currently I’m adding a typeahead input search box using AngularJS UI Bootstrap to search and view personal records.  The application is work in progress and will continue to evolve.  I am interested in any best practices and ways that I can build my knowledge around AngularJS.  Hopefully I can get feedback and blog about it here.

A few links that may help..

  1. AngularJS Google Group – https://groups.google.com/forum/#!forum/angular
  2. AngularJS documentation – https://angularjs.org/
  3. Dan Wahlin’s blog – http://weblogs.asp.net/dwahlin/default.aspx
  4. Angular Seed – https://github.com/angular/angular-seed

In the meantime, if I can help please leave a comment.