Communicating with the server with Angular « »
March 13, 2016
- $resource (ngResource)
- $http
- $http to READ
- $http to SAVE
- $resource with non Restful End Points
- Comparing promises from $http, $request and $q
- $http configuration
- $http Transforms
- Interceptors
- Restangular
$http is low level and $resource is high level and for Restful End Points.
$resource (ngResource)
We can use $resource for get calls that not are necesseraly resourceful.
The next example does server side logic in the client side, it is Bad practice. It is just an example.
Add the .js file
<script type="text/javascript" src="vendor/angular-resource.min.js"></script>
Add the dependency to the Module
var app = angular.module('app',['ngResource']);
Factories and Service
app.factory('users', function ($resource) {
return $resource('/data/users/:id', {id: "@id"});
});
app.factory('catalog', function ($resource) {
return $resource('/data/courses/:id', {id: "@id"});
});
// one Singleton to keep the User
app.value('identity', {});
Controllers
function LoginController (users,notifier,identity) {
users.query().$promise.then(function(userCollection) {
// userCollection is a simple Array
userCollection.forEach(function (user) {
if(name === user.name && password === user.password) {
notifier.notify('You have successfully signed in!');
identity.currentUser = user;
}
});
if(identify.currentUser === undefined) {
notifier.notify('Username/Password Combination incorrect');
}
});
}
function CatalogListController (catalog) {
var vm = this;
this.catalog = catalog.query();
}
function CatalogController (catalog,notifier) {
var vm = this;
this.registerCourse = function (course) {
course.registered = true;
course.$save();
notifier.notify('You have registered for '+ course.name);
}
}
$http
app.factory('followedInstructors', function ($http) {
return {
get: function() {
// ...
},
save: function() {
// ...
}
};
});
$http to READ
app.factory('followedInstructors', function ($http, $q) {
return {
get: function() {
// Solution1: This solution returns a promise
// return $http.get('data/userData/followedInstructors');
// Solution2: Also returns a promise but we move all the logic to the service
var dfd = $q.defer();
$http.get('data/userData/followedInstructors')
.success(function (data) {
dfd.resolve(data);
});
return dfd.promise;
},
save: function() {
// ...
}
};
});
Controller
function myController() {
var vm = this;
// Solution1: we use the success method of the promise
// followedInstructors.get().success(function(data) {
// vm.followedInstructors = data;
// });
// Solution2
vm.followedInstructors = follwedInstructors.get();
}
$http to SAVE
app.factory('followedInstructors', function ($http) {
return {
get: function() {
// ...
},
save: function(list) {
$http.post('data/userData/followedInstructors', list)
}
};
});
$resource with non Restful End Points
Usutally it isn’t a good idea to use $resource for not Restful End Points, but we can still use it if we are using a GET.
return $resource('data/userData/followedInstructors',undefined {
get: {method: "GET", isArray: true}
}).get().$promise;
Comparing promises from $http, $request and $q
$http
Returns a Promise
Methods
- then (config)
- catch
- finally
- success (data,status,header,config)
- error
To access data with the then method we have to use config.data.
$q
Returs a promise
Methods
- then (data)
- catch
- finally
$resource
returns an Array
All the data, plus to additional objects $promise and $resolved.
[$promise,$resolved]
// promise has another array with the elements, the $promise and boolean $resolved
$http configuration
return $http.get('data/userData/followedInstructors', {cache:true});
$http.post('data/userData/followedInstructors', list, {headers: {"ContentType": 'application/x-www-form-urlencoded'}
});
Configuring the App to have a default $http configuration
angular.module('app',[])
.config(function ($httpProvider) {
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
});
$http Transforms
Angular, for instance, has Transforms that do JSON serialization and deserialization for you automatically.
Transform Request
// Doing it this way my transformRequest goes first and then applies the rest of the default transformRequests.
$http.post('data/userData/followedInstructors', list, {
transformRequest: [
function (data, headersGetter) {
// to inspect the headers we have to call the headersGeterr function
// var headers = headersGetter();
for (var i = 0; i<data.length; i++) {
var item = data[i];
item.ts = new Date();
}
return data;
}
].concat($http.defaults.transformRequest);
});
Transform Response
// here the aprroach it's just the opposite, we put our changes the last.
return $http.get('data/userData/followedInstructors', {
transformRespone :
$http.defaults.transformResponse.concat([
function(data,headersGetter) {
return data.followedInstructors;
}
]);
});
Interceptors
Interceptors are very useful, for example, for Authentication tokens, or any thing that we need to add to each call.
We create the in the .config function and use the $provide.
Interceptors have 4 different methods:
- request
- requestError
- response
- responseError
angular.module('app',[])
.config(function($httpProvider, $provide) {
$provide.factory('myInterceptor', function() {
return {
response: function (config) {
if(config.config.url === '/data/courses') {
config.data.splice(5);
}
return config;
}
};
});
$httpProvider.interceptors.push('myInterceptor');
});
Restangular
- It’s a substitute for $resource.
- It has a dependency with lodash.
- You give it fragments of the URL and constructs the URL for you
app.config(function(RestangularProvider) {
Restangular.setBaseUrl('/data');
});
app.factory('users',function(Restangular) {
return Restangular.all('users');
});
function myController(users) {
users.getList().then(function(usersList) {
// do whatever
});
users.one(1).get(1).then(function (){});
uers.get(1);
users.one(1).all('followedInstructors').getList();
}