I am using $resource service for my crud operations now i want to get data on a condition like get appointments whose starting date is today. I am fetching all data by
vm.appointments = AppointmentsService.query();
and my service code is
(function () {
'use strict';
angular
.module('appointments')
.factory('AppointmentsService', AppointmentsService);
AppointmentsService.$inject = ['$resource'];
function AppointmentsService($resource) {
return $resource('api/appointments/:appointmentId', {
appointmentId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
})();
Now can i give condition in this code blockAppointmentsService.query({condition}); or change my service in node rest API.
If yes, then what will be my AppointmentsService.query call
For your different url path, you can create new method like below or you can pass startDate as a query string
Controller :
For Path Param
vm.appointments = AppointmentsService.searchByDate({date:'03/30/2016'});
For Query Param
vm.appointments = AppointmentsService.searchByDate({StartDate:'03/01/2016',EndDate:'03/30/2016'});
Service:
function AppointmentsService($resource) {
return $resource('api/appointments/:appointmentId', {
appointmentId: '#_id'
}, {
update: {
method: 'PUT'
},
// For Path Param
searchByDate :{
method : 'GET',
url : 'your url/:date'
},
// For Query Param
searchByDate :{
method : 'GET',
url : 'your url/:startDate/:endDate' ,
params : { startDate : '#StartDate', endDate : '#EndDate' }
}
});
}
Update your service code...
(function () {
'use strict';
angular
.module('appointments')
.factory('AppointmentsService', AppointmentsService);
AppointmentsService.$inject = ['$resource'];
function AppointmentsService($resource) {
var service = {
get: $resource('api/appointments/:appointmentId',{
appointmentId: '#_id'
},{
method:'GET'
}),
update: $resource('api/appointments/:appointmentId',{
appointmentId: '#_id'
},{
method:'PUT'
}),
query:$resource('api/appointments',{
method:'GET',
isArray:true
})
queryByStartDate:$resource('api/appointments/:startDate',{
startDate: '#_startDate'
},{
method:'GET',
isArray:true
})
}
return service;
}
})();
And call queryByStartDate inside controller
var startDate = new Date(); //you can use $filter to format date
$scope.appointments = AppointmentsService.queryByStartDate({startDate:startDate});
Related
I have an angular service based on meanjs for rents. Originally it looked like this:
(function () {
'use strict';
angular
.module('rents.services')
.factory('RentsService', RentsService);
RentsService.$inject = ['$resource', '$log'];
function RentsService($resource, $log) {
var Rent = $resource(
'/api/rents/:rentId',
{
rentId: '#_id'
},
{
update: {
method: 'PUT'
},
getByCarId:
{
method: 'POST',
params: {
rentId: 'bycar'
},
isArray: true,
hasBody: true,
requestType: 'json',
responseType: 'json'
}
}
);
angular.extend(Rent.prototype, {
createOrUpdate: function () {
var rent = this;
return createOrUpdate(rent);
}
});
return Rent;
// and all other function that are the same as down below
}());
Then I added a second resource
(function () {
'use strict';
angular
.module('rents.services')
.factory('RentsService', RentsService);
RentsService.$inject = ['$resource', '$log'];
function RentsService($resource, $log) {
var Rent =
{
basic: $resource(
'/api/rents/:rentId',
{
rentId: '#_id'
},
{
update: {
method: 'PUT'
},
getByCarId:
{
method: 'POST',
params: {
rentId: 'bycar'
},
isArray: true,
hasBody: true,
requestType: 'json',
responseType: 'json'
}
}
),
carUsageStats: $resource(
'/api/rents/car_usage'
)
};
angular.extend(Rent.basic.prototype, {
createOrUpdate: function () {
var rent = this;
return createOrUpdate(rent);
}
});
return Rent;
function createOrUpdate(rent) {
if (rent._id) {
return rent.$update(onSuccess, onError);
} else {
return rent.$save(onSuccess, onError);
}
// Handle successful response
function onSuccess(rent) {
// Any required internal processing from inside the service, goes here.
}
// Handle error response
function onError(errorResponse) {
var error = errorResponse.data;
// Handle error internally
handleError(error);
}
}
function handleError(error) {
// Log error
$log.error(error);
}
}
}());
Until I added second resource, this resolve function for creating new rent worked fine
newRent.$inject = ['RentsService'];
function newRent(RentsService) {
return new RentsService();
}
But when I added second resource (and had to address the one I want by using property name - cant use Rent.query() but Rent.basic.query()) instantiating new Rent no longer works. I added console log outputs around and code stops executing at line var rent = new RentsService(). Querying works fine. What is the correct way of making new object using service with multiple resources?
In the service.js file I have created two factories. Please let me know how to combine these two factories to one. So that I can import only one factory in my controller.
.factory('DeliveryReport', function($resource, API_URL) {
return $resource(API_URL + 'security/:userId/:timestamp/listOfDeliveries', {
userId : '#userId',
timestamp : '#timestamp'
}, {
update: {
method: 'PUT'
}
});
})
.factory('GuestReport', function($resource, API_URL) {
return $resource(API_URL + 'security/:userId/:timestamp/listOfGuests', {
userId : '#userId',
timestamp : '#timestamp'
}, {
update: {
method: 'PUT'
}
});
})
Is there a more elegant/correct way to compose an url with $http in AngularJS?
I find my self doing a lot of this:
$http.post('/api/' + model_id + '/' + id).success(function(data){
//do something ..
});
and wandering if there was something like this (a little more readable)
$http.post('/api/:model_id/:id', {param1, param2}).success(function(data){
//do something ..
});
Thanks
I use the following pattern:
o in a service called resources I create resources as follows (assuming my webservces are unter the URL path /webapi):
angular.module('myApp')
.factory('resources', function ($resource) {
var baseUrl = location.pathname + 'webapi';
return {
baseUrl: baseUrl,
myServiceResource: $resource(baseUrl + '/my/service/:pathParam'),
myOtherServiceResource: $resource(baseUrl + '/my/other/service')
// etc.
};
});
o in a controller or another service you can then simply reference the resources service and use the globally defined resources (which are created only once):
angular.module('myApp')
.factory('aService', function (resources) {
// pathParam matches the parameter :pathParam in the URL
// param1 and param2 are passed as query parameters
var parameters = { pathParam: "pathValue", param1: "aValue", param2: "anotherValue" };
var response = resources.myServiceResource.get(parameters, function() {
// do something on success
doSomething(response.result);
}, function(httpResponse) {
// do something on error
});
});
Not with $http directly, but it seems you are looking for $resource (https://docs.angularjs.org/api/ngResource/service/$resource).
Example from docs:
// Define CreditCard class
var CreditCard = $resource('/user/:userId/card/:cardId',
{userId:123, cardId:'#id'}, {
charge: {method:'POST', params:{charge:true}}
});
// We can retrieve a collection from the server
var cards = CreditCard.query(function() {
// GET: /user/123/card
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
var card = cards[0];
// each item is an instance of CreditCard
expect(card instanceof CreditCard).toEqual(true);
card.name = "J. Smith";
// non GET methods are mapped onto the instances
card.$save();
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
// server returns: {id:456, number:'1234', name: 'J. Smith'};
// our custom method is mapped as well.
card.$charge({amount:9.99});
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
});
// we can create an instance as well
var newCard = new CreditCard({number:'0123'});
newCard.name = "Mike Smith";
newCard.$save();
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
expect(newCard.id).toEqual(789);
I use the following pattern because it allows me to implement my own error handling logic when API calls is failed, also I found that it is readable and easy to understand.
angular.module('myApp')
.service('myService', function($http, $q) {
var baseUrl = location.pathname + 'webapi';
return({
setService: setService,
getService: getService
});
function setService(param1, param2) {
var request = $http({
method: 'post',
url: baseUrl,
params: {
param1: param1,
param2: param2
}
});
return ( request.then ( handleSuccess, handleError) );
}
function getService(param1, param2) {
var request = $http({
method: 'get',
url: baseUrl,
params: {
param1: param1,
param2: param2
}
});
return ( request.then ( handleSuccess, handleError) );
}
function handleError( response ) {
// Implement our own failure message if there is none
if ( !angular.isObject(response.data) || !response.data.message) {
return($q.reject("Failed to get data.") );
}
return($q.reject(response.data.message));
}
function handleSuccess( response ) {
return response;
}
});
I want the user to be able to set the slug name (URL) for a document in my app, but also I need some control so users don't override each other. It needs to be a separate call (not integrated with create/update) so the user can get visual feedback on their own slug name suggestions.
Therefore I've created a suggestSlug API call that takes an optional slug parameter as seed for the final slug name.
This is what my Express routes looks like:
app.get('/api/projects/suggestSlug/:slug', projects.suggestSlug);
app.get('/api/projects/suggestSlug', projects.suggestSlug);
app.get('/api/projects', projects.list);
app.get('/api/projects/:id', projects.show);
Now, I want to extend ngResource on the client side (AngularJS) to make use of this API:
angular.module('myapp.common').factory("projectModel", function ($resource) {
return $resource(
"/api/projects/:id",
{ id: "#id" },
{
update: { method: "PUT", params: { id: '#_id' } },
del: { method: "DELETE", params: { id: '#_id' } }
}
);
});
How do I extend the ngResource client to use my new API?
This was my solution: adding a separate $http-based method to my projectModel:
angular.module('myapp.common').factory("projectModel", function ($resource, $http) {
var projectModel = $resource(
"/api/projects/:id",
{ id: "#id" },
{
update: { method: "PUT", params: { id: '#_id' } },
del: { method: "DELETE", params: { id: '#_id' } }
}
);
projectModel.suggestSlug = function (slugSuggestion, callback) {
$http.get(
'/api/projects/suggestSlug/' + slugSuggestion
).success(callback).error(function(error) {
console.log('suggestSlug error:', error);
});
};
return projectModel;
});
Resource:
angular.module('TicketService', ['ngResource'])
.factory('Ticket', ['$resource', function($resource){
var Ticket = $resource('/api/tickets/:id1/:action/:id2',
{
id1:'#id'
},
{
list: {
method: 'GET'
},
listByOwner: {
method: 'GET',
params: {
action:'owner',
id1:"#id"
}
}
update: {
method: 'PUT',
params:{}
}
});
return ticket;
}]);
Query:
$scope.userTickets = Ticket.listByOwner({
id : $rootScope.user.id
}, function(){
//success
}, function(response){});
Result:
Angularjs builds a wrong url, /api/tickets but it should be /api/tickets/2/owner. Any ideas why?
The # indicates that angular should look for the attribute on the data object, which is the second parameter (optional) in the Ticket service methods. In the first parameter you specify the request parameters. There are two ways you can fix this:
Add an empty object as the first parameter
$scope.userTickets = Ticket.listByOwner({},{
id : $rootScope.user.id
}, function(){
//success
}, function(response){});
Or rename the request parameter object key (from id to id1):
$scope.userTickets = Ticket.listByOwner({
id1 : $rootScope.user.id
}, function(){
//success
}, function(response){});