Angular Client for CORs-enabled “Applications”

P.Madhanasekaran

Introduction

The title refers to a client for “Applications” in general, because the same JavaScript/Angular client code can access the CORS-enabled services provided by different server-side technologies: JEE, Dot.Net and Node. One can simply change the port no in the “url” and access the services.  Earlier we saw an Angular client for JEE Rest Services, which made use of “Angular seed”. What is Angular seed? It provides an application skeleton for a typical AngularJS web app and quickly bootstraps our angular web app projects and provides a development environment for these projects. In other words, it contains a sample AngularJS application and is preconfigured to install the Angular framework and a bunch of development and testing tools for instant web development gratification .It also shows how to wire two controllers and views together and the article showed how to customize the start-up provided by the “seed”  for our purpose. But the directory structure of the project generated with ‘seed’ has changed in later versions; so it has become necessary for us to have a re-look at the subject. 

Create a project:

After creating a HTML-5 project in NB, you have to install “angular”.  In NetBeans-8.0.1 you can right click on the project and install Angular and other components by invoking “npm install” from within the IDE itself. We can also go to the project folder in the command prompt and execute “npm install”. Angular-seed is pre-configured in such a way that “npm install” invokes “bower install” also. As pointed out above, the directory structure generated by the later version is different. So we will see the steps once again.

Steps

In NB choose File -> New Project. In the New Project Wizard choose HTML-5 under Categories and under Projects select HTML-5 Application and Click Next. Give your Project a name and Click Next. In the New HTML5 Application Wizard select AngularJS Seed and enable “Download Online Template” as shown in Figure-1 below. If you Click Finish the IDE will download Angular-seed which will generate a skeleton project, the structure of which will be as under: 

 



Site Root/         -->  root folder for all the source files for the application
  app.css               --> default stylesheet
  components/           --> all app specific modules
    version/              --> version related components
      …..

  view1/                --> the view1 view template and logic
    view1.html            --> the partial template
    view1.js              --> the controller logic
    view1_test.js         --> tests of the controller
  view2/                --> the view2 view template and logic
    view2.html            --> the partial template
    view2.js              --> the controller logic
    view2_test.js         --> tests of the controller
  app.js                --> main application module
  index.html     --> app layout file (the main html template file of the app)
  index-async.html      --> just like index.html, but loads js files asynchronously

```

After you execute “npm install” under “Site Root” you will see one more sub-folder “bower_components” with necessary sub-folders and angular files.

Figure-1

“Services” Component

We have discussed this Angular component earlier. The controller component in Angular is closely tied to a view and hence should have only “presentation logic”. To hold “business logic” of the application which will be shared by other components, especially multiple controllers, Angular provides “services” component. There will be only one instance of a particular “services” component during the life-time of an application (Singleton).

It can contain code to request and store and manipulate data from external servers which can be used by many controllers. Right click on /components and choose Newà JavaScript File and give it the name services. The IDE will append the suffix “js”. The generated file can be filled up as under:

angular.module('myApp.services', ['ngResource']). //--------1
factory('Emps',function($resource){  // ------2)
return $resource('http://localhost:3000/api/employees', {},{   //--------3)
findAll:{method:'GET', isArray:true }
});
});

  1. The module is named “myApp.services”. The module ‘ngResource’ which is found in  angular- resource is specified as a dependency and the framework will inject the same.
  2. Factory() is one of the functions is angular.module and is used here to create a “services” component.
  3. The function makes use of $resource service provided by ‘ngResource’ module and injected by the framework, as it is declared as an argument to the function. “Emps” is a Sresource class representation and can make use of the methods defined in the $resource class.
  4. The $resource() function takes three arguments a)full END-POINT url b) parameters, if any, 3) some custom action, in this case, findAll().

Angular-resource, as mentioned earlier, is an optional sub-project under Angular and the “index.html” found in the skeleton generated by “seed” will not have reference to it. For the framework to inject ‘ngResource’ module, the declaration of angular-resource in” index.html “under <script></script> is necessary. Add the following to the <script> tag in the above file:

  1. <script src="bower_components/angular-resource/angular-resource.js"></script>.
  2. <script src="components/services.js"></script> // the file  containing “myApp. services” module we coded now.
  1. Angular-resource is a separate sub-project under Angular. It has to be separately added , as it contains the module  ‘ngResource’ which is declared as a dependency to “myApp.services” and the framework should know where to find it.
  2. This declaration is necessary , as the module “myApp.services” is specified as a dependency to the module “myApp.view1” below and we should tell the framework where to find it.

The generated “view1.js” is given below:

view1.js

'use strict';
angular.module('myApp.view1', ['ngRoute']) //  ------1)

.config(['$routeProvider', function($routeProvider) {  //---2)
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}])

.controller('View1Ctrl', [function() {  //--------3)

}]);

  1. To the module ‘myApp.view’ , ‘ngRoute’ has been declared as a dependency. The ‘index.html’ in the skeleton contains” <script src="bower_components/angular-route/angular-route.js"></script>” to tell the framework where to find it. The ”angular-route” is also a separate sub-project. We will add one more dependency – the “services” component coded by us.
  2. We need not touch “config” object which wires controller and view together.
  3. We have to fill up the generated skeleton controller function.

The completed “view1.js” may look as under:

'use strict';

angular.module('myApp.view1', ['ngRoute','myApp.services'])

.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}])


.controller('View1Ctrl', function($scope,Emps) {
$scope.emps = Emps.findAll();    //--------1)
});

  1. See how findAll() we defined in the “services” component is invoked without instantiating “Emps”- the name we gave to the $resource class representation. The value returned is stored in the variable “emps” in $scope. You know the view tied to a controller can access the model stored by the controller in its $scope.

view1.html

<p>This is the partial for view 1.</p>
<table>
<tr ng-repeat="e in emps">  //-----1)
<td>{{e.Name}}</td>
<td>{{e.Department}}</td>       
</tr>
</table>

  1. The syntax of ‘ng-repeat’ is similar to “for each”.

Likewise, the generated “view2.js” can be filled up as under:

view2.js

'use strict';

angular.module('myApp.view2', ['ngRoute','myApp.services'])

.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view2', {
templateUrl: 'view2/view2.html',
controller: 'View2Ctrl'
});
}])

.controller('View2Ctrl', [function($scope,Emps) {
$scope.name = '';
$scope.department = '';
$scope.save = function() {
Emps.save({Name : $scope.name, Department: $scope.department}, function(response) {
if (response) {
$scope.notification = 'Employee is saved';
$scope.name = '';
$scope.department = '';
} else {
$scope.notification = 'Employee is not saved';
}
});
};
}]);



view2.html

<p>This is the partial for view 2.</p>
<p>
<span>Name</span><input ng-model="name"/><br/>
<span>Content</span><input ng-model="department" /><br />
</p>
<p>
<span>{{notification}}</span>
<button ng-click="save()">Save</button>
</p>

Run the application

We need to first start the MongoDB server by going to the (MongoDB installation\bin) in the Command Prompt and executing

mongod  --dbpath(path to your data directory).

In another instance of the Command Prompt, go your express application folder and execute
node app
If you see the message listening on 3000
Go to NB and run your Angular client Project.

Add to Chrome

In the tool bar if you see “Chrome” , you will see Figure-2. Click Go to Chrome Web Store. You can “NetBeans Connector” in Chome with the button

 

When you click the button you will see Figure-3. You will be asked to re-run the Project.If you do the same You see view1 in Figure-4.If you click view2 you will Figure-5.You can add some data as shown in Figure-6 and click “Save”.You will see the message “Employee is saved”.If you click view1 now you can see also in the employees list, the record you added now.

The sample there can be used except the Controller there with a few modifications. The EmployeesController.cs  there,  is reproduced below for the sake of convenience.

EmployeesController.cs

public class EmployeesController : ApiController
{
public IEnumerable<Employee> GetAll()
{
StaffManager manager = new StaffManager();
return manager.GetEmployees();
}
}

To enable CORS, the code can be modified as under:

{
public HttpResponseMessage GetAll()
{
StaffManager manager = new StaffManager();
var employees = manager.GetEmployees();
var response = Request.CreateResponse<IEnumerable<Employee>>
(HttpStatusCode.OK, employees);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;

        }
}

If you compare this with the earlier controller code you can note the following:
While the earlier controller returned the CLR object IEnumerable<Employee>, now it is 

returning “HttpResponseMessage”. Look at the MessageProcessing Pipeline of Web API in Figure-8.The Browser will get always  only a HttpResponseMessage, as the framework will convert the CLR object returned by the controller into a HttpResponseMessage. Now instead of leaving the conversion job to the framework, the controller itself returns an HttpResponseMessage. By returning an object of type HttpResponseMessage, we can have better control over what is returned to the client.  Here we are able to set the response header Access-Control-Allow-Origin with value of * and enable CORS.

To enable “POST” also, add the following methods also

public bool Post(Employee employee){

manager.Add(employee);
return true;
}
public HttpResponseMessage Options()
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
return response;
}


Add to StaffManager.cs the method Add(),which the above Post() invokes.

public void Add(Employee employee)
{
DbSet<Employee> employees = Db.Employees;
employees.Add(employee);
Db.SaveChanges();
}

Run the Web API project

Run the Web API through Debug à Start Debugging and ascertain the port in which the application is running. The port no in “services.js”can be modified accordingly. In my case the port is “3376”; so port there was modified from “3000” (for Node) to “3376”.You can save the file and run the application. Chrome will open and appear as in Figure-9 displaying the records. You can click view2 and add a record. If you click view1 now, you can see the recently added record also.

Conclusion

There is a ‘cors’ middleware for Express Applications. There is a package “Microsoft.AspNet.WebApi.Cors”. They may be useful when we want to fine tune the requests for CORS . For smaller apps,  it is sufficient to add  through code the response headers - “Access-Control-Allow-Origin and “Access-Control-Allow-Headers”. We can create one more Web API project in Visual Studio to act as a client for our CORS-enabled Web API project. But, as shown above, it is easier and even advisable to create a HTML5 project in NetBeans IDE to act as a client. We can choose any JavaScript library of our choice- JQuery, Angular etc. Remember, the HTML-5 client in NetBeans can make use of the services any server side technology –Node or JEE or Dot Net .Here it accesses REST API in an Express Web Application; the same code was used to access a web services from ASP Net Web API also.

 

 








}