So let’s have a look at how to install and use Google’s interface framework Angular in a .Net MVC4 project.
Installation
This one is as easy as get into NuGet and installing AngularJS from there, it will install lots of libraries and make some changes on your webconfig but it should just work.
Hello World!
Now let’s make an MVC Controller, add it a View without using the layout (just to simplify the example) and no need of any Model for now.
public class AngularController : Controller { public ActionResult AngularBasicExample() { return View(); } }
Once we have that, we need to set the directive ng-app to the HTML tag like this:
<!DOCTYPE html> <html ng-app> ... </html>
That will tell Angular.js that this page is an “angular application”, or in other words, that it should look for more angular directives in the document to make them work. This is a good approach to improve client’s performance: no ng-app directive, no angular checking anything. But of course if we want angular to be on the page we need to make a call to the script, let’s add this on the head just to continue with this example:
<script src="~/Scripts/angular.js"></script>
Let’s write our Hello World then:
<div> {{ 'World' | greet }} </div>
The double brackets will tell angular to execute the code inside of them, in this case, we are sending a string and then using an angular function to play with it, greet will say us Hello, in this case the output will be: “Hello, World!”.
Playing with the View
Now, let’s just play with Angular a bit more to understand how the View works:
<p>1+1 = {{1+1}}</p>
That will display 1+1 = 2 (thanks to Stephane for this example!)
Playing with the Model
We are going to bind an HTML input with the angular application’s model, then, we will display what’s on the model just next to the input:
<body> <input type="text" ng-model="WelcomeText" /> {{ WelcomeText }} </body>
With that example we can see how will angular bind input values to the model in real time, as you can see that what you write on the input goes to the model and what’s more impressive, it automatically refreshes the displaying field.
Did you notice I didn’t write any javascript? I didn’t declare the model, nor did I declare its properties, it just works. On writing {{WelcomeText}} angular will look for that variable on the model/context, and as we bound an input to such variable angular will know to do the rest.
Creating our first Controller: Using Static Data
Now let’s use some data to play with this for real, it’s time to start creating a Controller to get the data and assign it to the View. To create a controller with angular we will need to start writing some javascript (you can save it on a file but let’s add it to the page to simplify for now):
<script src="~/Scripts/angular.js"></script> <script> var app = angular.module('BasicApp', []); </script>
First of all, we create an angular application and give it a name, we’ll need to add that name to our View html tag so that angular knows which app to use for this page-view:
<!DOCTYPE html> <html ng-app="BasicApp"> ... </html>
Now notice that when I declared the app variable I was instantiating a module, that’s because Angular doesn’t have a main method that will handle the different parts of the application, instead, it uses modules that will specify how the application should work. This has some good points:
- The declarative process is easier to understand.
- You can package code as reusable modules.
- The modules can be loaded in any order (or even in parallel) because modules delay execution.
- Unit tests only have to load relevant modules, which keeps them fast.
- End-to-end tests can use modules to override configuration.
That being clarified, we are going to add a controller to the angular application’s module:
<script src="~/Scripts/angular.js"></script> <script> var app = angular.module('BasicApp', []); app.controller('UsersController', function ($scope) { // Static data $scope.userProfiles = [ { "id": 1, "name": "Peter", "age": 21 }, { "id": 2, "name": "Alex", "age": 22 }, { "id": 3, "name": "Ellia", "age": 45 }, { "id": 4, "name": "Andrew", "age": 53 } ]; }); </script>
All the controllers are declared with that scope variable which has the controller context (including the Model), that is to help us later to use dependency injection for unit testing. That said, in this example we are just declaring some static data inside the controller (somehow, feels like if we were doing a unit test actually). Now that we have the controller ready with some data, it will handle it inside the View, let’s see how to assign it to the View:
<div ng-controller="UsersController"> Search: <input type="text" ng-model="searchText" /> {{ searchText }} <h3>Users</h3> <table> <tr ng-repeat="usr in userProfiles | filter:searchText"> <td>{{ usr.name }}</td> <td>{{usr.age | currency : "£"}}</td> </tr> </table> </div>
First of all, the good point of this controller is that it won’t look over all the page but just were it is expected to work, that’s why we use the ng-controller directive to tell the controller where’s its “View” (which is a piece of HTML in here, not the full page). That done, we use the ng-repeat directive to write all the elements in our collection (as a foreach would do), and finally, we just access the Model getting userProfiles which if you remember was assigned to the controller’s scope, inside it we just access the elements properties as they were declared on JSON (note that this can come like this from the server, so you don’t need to previously declare them).
Just as an addition to this example, of which you can see a better explanation by Dan Wahlin on the Ng-Conf 2014, we added two more angular directives: filter and currency, filter allows us to set a variable to filter the elements looking at any of its properties (if you make this example, notice that on writing 3 the element with the id 3 also appears even though there isn’t any 3 on it’s visible properties), and currency will add the currency symbol to the value (which in my example is an age, but just get the point), the default symbol is the dollar but I live in the UK 😉
Displaying server data (AJAX calls)
Now let’s create a service to retrieve some random data to check how getting data with Angular using AJAX. This will be our Model and Action:
public class UserModel { public int ID { get; set; } public string Username { get; set; } public string Name { get; set; } public string Surname { get; set; } public int Age { get; set; } public string Description { get; set; } public string Photo { get; set;} public string Address { get; set; } public static List<string> Names = new List<string>() {"Arya", "Cersei", "Aegon", "Catelyn", "Rhaegar", "Bran", "Daenerys", "Eddard", "Tywin", "Ellia"}; public static List<string> Surnames = new List<string>() { "Martell", "Frey", "Snow", "Targaryen", "Lannister", "Stark", "Tully", "Baratheon", "Tyrell", "Calatayud" }; } public class UsersController : Controller { public JsonResult Get(int amount) { List<UserModel> result = new List<UserModel>(); Random rnd = new Random(); for (int i = 0; i < amount; i++) { var user = new UserModel() { ID = i, Name = UserModel.Names[rnd.Next(UserModel.Names.Count)], Surname = UserModel.Surnames[rnd.Next(UserModel.Surnames.Count)], Age = rnd.Next(99), Photo = "", Address = "Some Street, London", Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip " + "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit " + "esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum." }; user.Username = user.Name + user.Surname + user.Age; result.Add(user); } return Json(result, JsonRequestBehavior.AllowGet); } }
Now let’s just get that using an AJAXcall with Angular:
<script> var app = angular.module('BasicApp', []); app.controller('UsersController', function ($scope, $http) { $http.get('http://localhost:56319/Users/Get?amount=20') .then(function (response) { $scope.userProfiles = response.data; }); }); </script>
It’s quite the same as before only that the data is coming from the server instead than being statically placed there. Also, I had the properties declares in lowercase on previous example, but now the ones coming from the Model are capitalized, so make sure you change that:
<div ng-controller="UsersController"> Search: <input type="text" ng-model="searchText" /> {{ searchText }} <h3>Users</h3> <table> <tr ng-repeat="usr in userProfiles | filter:searchText"> <td>{{ usr.Name }} {{ usr.Surname }}</td> <td>{{ usr.Age | currency : "£"}}</td> </tr> </table> </div>
[…] so after checking how the basics of Angular work on a single page and the different ways to create a controller in Angular it’s time to […]