Web application developer

CRUD with Angular-resource and WebApi

monackfr angular asp.net-mvc web-api

Written by: willem | Feb 7 2016 8:35 PM

For my application framework I want to dynamically load asp.net mvc views and use angular to load the JSON data into these views. To accomplish this I made a proof of concept of a simple CRUD that uses angular-ui-router to load the views and angular-resource to load the data. Server side I use Asp.net MVC and the WebApi library. In this post I will explain step by step this method.

For this application I created a Asp.net MVC project and added WebApi with Nuget. I also downloaded the javascript libraries Angular, Angular-ui-router and Angular-resource.

First I created an index page. From this page all scripts and templates will be loaded. This page should be the default page that is loaded on application startup. Next I created an Angular module called ‘myApp’. I also load the modules ui-router and resource in this module.

	var myApp = angular.module('myApp', ['ui.router', 'ngResource']);

Then I configured the ui-router:

	myApp.config([

	        '$stateProvider', function ($stateProvider) {

	             $stateProvider

	                 .state('suitcases', {

	                     url: '/suitcases',

	                     templateUrl: 'suitcase/index',

	                     controller: 'suitcaseController'

	                 })

	                 .state('suitcases.add', {

	                     url: '/suitcase/add',

	                     templateUrl: 'suitcase/addSuitcase',

	                     controller: 'addSuitcaseController'

	                 })

	                 .state('suitcases.edit', {

	                     url: '/suitcase/edit/:id',

	                     templateUrl: 'suitcase/editSuitcase',

	                     controller: 'editSuitcaseController'

	                 })

	                 .state('suitcases.delete', {

	                     url: '/suitcase/delete/:id',

	                     controller: 'deleteSuitcaseController'

	                 })

	                 .state('suitcases.detail', {

	                     url: '/suitcase/:id',

	                     templateUrl: 'suitcase/detailSuitcase',

	                     controller: 'detailSuitcaseController'

	                 });

	         }

	     ]);

I created 5 page states. A page state is a situation a page can be in. It combines an URL with a view and a controller. For example the 'suitcases' page state is created for showing a list of suitcases. The URL is the page url with #suitcases added to the url. If this url is entered it wil load the view from suitcase/index and the suitCasecontroller. So every state has a:

  • URL – this is added to the url after the # in the browser, and makes back and forward buttons work. It also let you copy and paste urls to link directly to an application state
  • templateUrl – this is where the template is found and at this url asp.net mvc should return the html you want to load. So this will be a (razor) view somewhere in the app. The result of this will be loaded into the tag that has the ui-view attribute.
  • controller – the angular controller that will be loaded and in scope of the loaded view.

The folowing code declares the main controller. This is the controller that is linked to the index html and doesn’t need to do anything. It needs to be declared though since the controllers of the dynamically loaded views will be under this one in the scope.

	         angular.module('myApp').controller('baseController', function ($scope) {
	            
	         });

 

Next the nested controllers are declared. I will explain the first one, the others are practically the same.

	angular.module('myApp').controller('suitcaseController', function($scope, $state, Entry) {

	            $scope.loadEntries = function () {
	                 var entries = Entry.query(function() {
	                     console.log(entries);
	                     $scope.suitcases = entries;
	                 });
	             };

	            $scope.delete = function (suitcase) {
	                 var params = { id: suitcase.Id };
	                 suitcase.$delete(params, function () {
	                     $scope.loadEntries();
	                     $state.go('suitcases');
	                 });
	             };

	            $scope.loadEntries();
	         });

This is a basic angular controller and contains two methods: loadEntries and delete. LoadEntries is run on default when this controller is loaded. The delete method is put here because the list shown bij loadEntries has a delete button which lives in the scope of this controller.

The view that belongs to this controller looks like this:

	<div>
	     <h2>SuitCases</h2>

	    <ul class="nav2">
	         <a ui-sref="suitcases.add">Add Suitcase</a>
	     </ul>

	     <div ng-repeat="suitcase in suitcases">
	         <a ui-sref="suitcases.detail({ id: suitcase.Id })">
	             {{suitcase.Id}}
	             {{suitcase.Locked}}
	             {{suitcase.Wheels}}
	         </a>
	         <a ui-sref="suitcases.edit({id:suitcase.Id})">edit</a>
	         <a href="" ng-click="delete(suitcase)">delete</a>
	     </div>
	    
	     <section ui-view></section>
	</div>

It has several interesting hyperlinks in this view. The Add Suitcase link has a ui-sref attribute. This tells the router module that it should go to the link defined at the given state (in this case suitcases.add). If you click on this hyperlink the router will load the view and the controller that is configured for this state. See the ui-configuration and look for this part to see how it is configured:

	.state('suitcases.add', {
	                         url: '/suitcase/add',
	                         templateUrl: 'suitcase/addSuitcase',
	                         controller: 'addSuitcaseController'
	                     })

Within the ng-repeat in the view (a loop in angular) you see suitcases.detail({id:suitcase.Id}) defined in the ui-sref. This works the same as the previous add suitcase link with the difference that the suicase id is sent as a paramater. In the router configuration, the paramter “id” is picked up and made available to the controller:

	.state('suitcases.detail', {
	                         url: '/suitcase/:id',
	                         templateUrl: 'suitcase/detailSuitcase',
	                         controller: 'detailSuitcaseController'
	                     });

The edit suitcase part works the same as the detail suitcase. So I wont go in detail with that. The delete instructions however are slightly different.

The delete method lives in the scope of the suitcaseController. Therefore this method van be called directly withoud the use of the router. There is one thing however to keep in mind: in the web.config you should add next tag to the system.webserver section. If you don’t, the webserver will not accept delete requests from the angular-resource module.

	<modules runAllManagedModulesForAllRequests="true">

The next thing is configuring the resource module.

	///
	/// Factory for resource library
	///
	 angular.module('myApp').factory('Entry', function ($resource) {

	    return $resource(
	         "api/suitcaseapi/:id", { id: '@@id' },
	         { "update": { method: "PUT" } }
	     );
	 });

Which is pretty straightforwarde: you tell the resource module that the web api can be reached at api/suitcaseapi/. For updates I choose to use the put method, which is not a default setting for the resource module so you need to change that setting.

You can download the complete source at my github account.

No Comments

Add a Comment

About Me

I'm a web application developer specializing in asp.net. I have skills in asp.net, C#, html5, javascript, asp.net mvc, design patterns and more.

more about me

Random background module

This module for Orchard CMS lets you upload a list of images. For every page it chooses one randomly and sets it a the background image.

Go to project page on CodePlex
Download module

The Monack Framework

This open source framework makes it easy to build and develiver custom web applications. Unfortunately I can't spent much time on it so it is still work in progress. 

More about MonackFr
Project page at CodePlex

Orchard

Since I decided to create this website in Orchard and didn't know anything about
it when I started, I also post my experiences with this CMS.