segunda-feira, 4 de agosto de 2014

How to access a .Net webservice from AngularJS

This tutorial shows you a way to access .Net Web Services.
We will use Visual Studio 2008 and .Net 3.5 framework. To make it simpler as possible we will not use web api, just plain old .net services.

 First let's create the .net part. Open up Visual Studio and create a 'New Web Site...'(shift+alt+N), for the type of the web site choose 'ASP.NET Web Service', in the name put what you want, and in the language choose 'Visual C#'. Click the OK button. Go to 'Solution Explorer' and double-click on the 'App_Code\Service.cs' file. First let's create a class for holding the clients:
  public class client
    {
        public string name { get; set; }
        public string company { get; set; }

        public client()
        {
        }

        public client(string name, string company)
        {
            this.name = name;
            this.company = company;
        }
    }
 
Then we will create the method that exposes the clients:

  [WebMethod()]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true)]
    public List getData()
    {
        List clients = new List();
        clients.Add(new client("Philip J. Fry","Planet Express"));
        clients.Add(new client("Homer J. Simpson", "Nasa"));

        return clients;
    }
 
you should also uncomment the line:

 \\ [System.Web.Script.Services.ScriptService]
 
In web.config add the following inside the /<system.web/>:

 <webServices>
        <protocols>
          <add name="HttpGet"/>
          <add name="HttpPost"/>
        </protocols>
    </webServices>
 
The .Net part is done. You can now start the service (CTRL+F5). In the top of the page you'll have the two available methods, click on getData and then on 'invoke' and copy the given url.

  Now with the AngularJS part. I used Yeoman to create the project and file structure. To install Yeoman you can follow thistutorial. After you install it, go to command line and create a folder (my case was 'aspNetWebService') and, inside that folder, type "yo angular". Answer 'No' to the 'Would you like to use Sass (with Compass)?' and 'Yes' to the 'Would you like to include Bootstrap?'. In the dependencies you can uncheck everything because it's out of the scope for this tutorial.
 Let it finish creating your project and then load the project on you favorite IDE (I use JetBrains WebStorm). Edit your app.js file to look like this:


 angular.module('aspNetWebserviceApp',[]); 
 
In the controllers folder, you can delete all the content from controller.js and put the following code:
 "use strict";

 var myControllers = angular.module('aspNetWebserviceApp.controllers',[]);
 
Go back to the app.js and inject the controller dependency:

 
    angular.module('aspNetWebserviceApp',['aspNetWebserviceApp.controllers']); 
 
Now all of your controllers are in one place, and accessible throughout the app. To access the web service we use a service. In angular you'll have the following service options: 
 service, factory, value, constant and provider. 
 In this app we'll use the service. Create a 'services' folder inside your 'scripts' and then create a .js file called 'aspNetService.js'. Inside the newly created file put the following code:

 "use strict";

 var myServices = angular.module('aspNetWebserviceApp.services',[]);

 myServices.service('clientsService', function ($http, $q) {
  this.getClients = function () {
   var deferred = $q.defer();
   $http({
    data:{},
    method:'GET',
    headers:{
     'Accept': 'application/json, text/javascript, */*; q=0.01',
     'Content-Type': 'application/json; charset=utf-8'
    },
    url:'http://localhost:58116/clients/Service.asmx/getData'
   })
    .success(function (data, status, headers, config) {
     deferred.resolve(data.d);
    })
    .error(function (data, status) {
     deferred.reject("Error: "+data.d);
    });
   return deferred.promise;
  }
 });
 
In the line
 
 myServices.service('clientsService', function ($http, $q) {
 
we inject two dependencies, $http and $q:
  • $http - a service designed to access remote HTTP servers via XMLHttpRequest or JSONP. (very similar to $jQuery's $.ajax() method)
  • $q - Implements promises.
Then, we have the method that return client data:
 
 this.getClients = function(){
 
we start by creating a defer object which hold up the result of the call, in the form of a promise, either a success or a failure.

 
 var deferred = $q.defer();  
 
then we connect to the web service by using:

 
 $http({
            data:{},
            method:'GET',
            headers:{
                'Accept': 'application/json, text/javascript, */*; q=0.01',
                'Content-Type': 'application/json; charset=utf-8'
            },
            url:'http://localhost:58116/clients/Service.asmx/getData'
        });
 
If you used the $.ajax jQuery method you'll notice the similarities. Since we're only retrieving data, the 'data' parameter is empty, also for the same reason, the 'method' parameter will be 'GET', and in the header we specify that the response will be in JSON format. Lastly we put the webserver url(Did you save it?) in the 'url' parameter. And that's it. After that we must, based on the data retrieved, fill the deferred object.
 
            .success(function (data, status, headers, config) {
                deferred.resolve(data.d);
            })
            .error(function (data, status) {
                deferred.reject("Error: "+data.d);
            });
and return it:
 
 return deferred.promise;
 
the service part is done. Now let's get back to the app.js and inject the services dependency:
 
 angular.module('aspNetWebserviceApp', ['aspNetWebserviceApp.controllers','aspNetWebserviceApp.services']);
 
In the controllers js file, inject the service:

 myControllers.controller('mainCtrl',function ($scope,clientsService)
 
and create an empty container for the clients data:

 $scope.clients = [];
 
then we fill this array:

 $scope.getClients = function () {
        clientsService.getClients()
            .then(function (data) {
                $scope.clients = data;
            })
    }
 
In this method we call the getClients() from the service we previously created and, in case of success, assign the income to the clients array. If you want, you can load up the data when the page loads by creating the following function in the controller:

 $scope.init=function(){
        this.getClients();
    }
 
In your index.html file remember to link to the services file: (if you're using webstorm type 'script:src' tab and copy the path to the js file)
 <script type="text/javascript" src="scripts/services/aspNetService.js"></script>
 
Then erase html markup inside (leave the script tags) and create the following
:
 <div ng-cloak="" ng-controller="mainCtrl" ng-init="init()">
  <table class="table table-stripped">
<tr>
    <th>Name</th>
    <th>company</th>
   </tr>
<tr ng-repeat="client in clients">
    <td>{{client.name}}</td>
    <td>{{client.company}}</td>
   </tr>
</table>
</div>
The ng-controller="mainCtrl" is to indicate that the data inside the div will come from the "mainCtrl" controller, the ng-init="init()" calls the preload function we created, and ng-cloak="" hides those ugly {{ }} from view, displaying only the data when it is in his final state. Then we create a table to show the data from the controller.
<tr ng-repeat="client in clients">
   <td>{{client.name}}</td>
   <td>{{client.company}}</td>
 </tr>
These lines show another cool feature in AngularJS, the ng-repeat directive. Basically, it iterates through clients collection and for each one of the clients creates a table row with two columns, name and company of the client. Probably, the data will not show up and that because of the following error (this was on Chrome):

XMLHttpRequest cannot load http://localhost:58116/clients/Service.asmx/getData. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access.

This is because we are accessing another server in the same host. To solve this in Chrome you can do the following. Go to Task Manager and close every instance of Chrome. Then, create a shortcut to chrome on the desktop and set the target to: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security Now, start this Chrome and load the webservice and the angular app. And you'll see that the data will load up quite nicely.

Conclusion:

Of course this is a very simple example of how to access a ASP.NET web service from AngularJS. But it shows how powerful and clean AngularJS is. In a future post I will show you how to send data to an ASP.NET Web Service.

terça-feira, 15 de julho de 2014

A basic directive - Text Emphasis


  Nothing better than a real-world example to show why directives are so important.
  As you may already read somewhere (or everywhere), directives teach new tricks to HTML. 
  Let's start. Imagine you need to put some emphasis in certain words in your site. In angular, you can create a directive for that and use it wherever you want.


Let's go with the basic module and controller configuration
var app = angular.module('myApp',[]);

app.controller('myCtrl',function($scope){
});

Then let's create the directive
// you start by defining the name and callback function

app.directive('myDir',function(){
return{
restrict: 'E', // it'll be an element,
// and in html will be called by <my-dir>
// other options: 'A'ttribute, 'C'lass, co'M'ment
scope: {}, // isolated scope (will do a post about this)
link:
// this function will manipulate the DOM, if you wan't to
// play with jQuery you must use it here.
function(scope,element,attrs){
element.on('mouseenter',function(){
// when the mouse enters the word, a border will be applied to it
// and the size augmented.
$(this).css({'border':'1px solid #000;','font-size':'150%});
});
// now we need to remove the styles when the mouse leaves the word
element.on('mouseleave',function(){
$(this).css({'border':'none','font-size':'100%});
});
}
});
To apply it you need call the directive in your html like this:
  hello <my-dir>World</my-dir>
This is a simple example of how powerfull, yet simple, directives are. In very few lines of code, I did a component that I can use throughout my application, keeping the html clean and easier to read. You can check Demo Here.

segunda-feira, 19 de maio de 2014

WebStorm tip: surround text with tag

Select the text you want to surround with a tag and then press ctrl+alt+t, select the option <tag></tag> and then write the command.