Calling REST API with parameter - angularjs

I'm trying to create a product browser. I wrote simple HTML view code with a text field, button and result list. I also wrote REST API GET method with the parameter which query objects by ID. Url of my view is #/Products but REST method URL #/Products/Id
REST GET
#Path("/{id:[0-9][0-9]*}")
#Produces("application/json")
public Response findById(#PathParam("id") Long id) {body}.
Now I'm trying to write controller to #/Product view
angular.module('searchingPage').controller('SearchProductsController', function($scope, $http, $filter, ProductResource ) {
$scope.search={};
$scope.performSearchById = function() {
//goal $scope.searchResults = ProductResource.findById($scope.search.id);
};
})
How can I call my REST API with parameter and right path with Id in it?

the '#' sign use for client side not server side, your rest method url is probably something like "api/Products/Id". you can simply call rest method as below
$scope.performSearchById = function() {
$http({
url: 'api/Products/' + $scope.search.id,
method: 'GET'
}).then(function(data){
$scope.searchResults = data.data;
})
};
}

Related

How to contact a non-standard API using Angular ngResource

The API I am using requires a non-standard where clause if I try to search for a particular non-id field. The endpoint I need is:
http://127.0.0.1:4001/api/testusers/findOne?userName=Anton
So this will find me the first record in the testusers table whose column (userName) = 'Anton'.
My standard service is:
angular.
module('shared.testUser').
factory('TestUser', ['$resource',
function($resource) {
return $resource('http://127.0.0.1:4001/api/testusers/:id', {id:'#id'},//parameters
{
update: {
method: 'PUT' // To send the HTTP Put request when calling this custom update method.
}
});
}
]);
and my calling function is:
self.checkUsersEntryDirection = function(){ //NOT WORKING
self.testuser = TestUser.get({ username: 'anton' }, function() {
console.log(angular.toJson(self.testuser));
}); // get() returns a single entry
}
Clearly this doesn't work and I can't use the standard get approach. Can anyone think how this can be achieved?
You could create a secondary factory TestUserByName, and make the following changes:
angular.
module('shared.testUser').
factory('TestUserByName', ['$resource',
function($resource) {
return $resource('http://127.0.0.1:4001/api/testusers/findOne?userName:username', null,
{
update: {
method: 'PUT' // To send the HTTP Put request when calling this custom update method.
}
});
}
]);
Call the get action method with two parameters:
var params = {id: "findOne", username: "anton"};
self.checkUsersEntryDirection = function(){
self.testuser = TestUser.get(params, function() {
console.log(angular.toJson(self.testuser));
}); // get() returns a single entry
}
The id parameter will override the default and username parameter will be added as a query string.
From the DOCS:
Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?.
Given a template /path/:verb and parameter {verb:'greet', salutation:'Hello'} results in URL /path/greet?salutation=Hello.
--AngularJS ngResource $resource Service API Reference

how to have angularJS post data to MVC controller which redirects to a view

I am posting some data to an MVC action method using AngularJS. This action method will either show its backing view or redirect to another page. Currently all that is happening is the data is getting posted but the redirect is not happening via MVC. I am getting this done using angular's window.location method. I want to know if there is a better way or if I need to post differently using Angular.
On page A I have angular scripts posting data to page B like below:
serviceDataFactory.POST('http://localhost:1234/home/B', someData, pageConfig).then(function () {
//on success
window.location = 'http://localhost:1234/home/Index';
},
function() {
//on error
window.location = 'http://localhost:1234/home/B';
});
This is my service factory
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
var d = $q.defer();
$http({
method: 'POST',
url: url,
data: postData,
config: conf
}).success(function(data) {
d.resolve(data);
}).error(function(error) {
d.reject(error);
});
return d.promise;
}
return service;
}
);
On Page B I want to redirect to another page. This is my page B in MVC
[HttpPost]
public ActionResult B(string someData)
{
//recieve string someData and perform some logic based on it
.
.
.
if(boolCondition)
return RedirectToAction("Index", "Home");
else
return View();
}
Here once Angular posts to the action method B, it executes all the code all the way till the if(boolCondition) statement. Since I am unable to have that redirect affected via MVC, I do that in Angular itself using the success or error block that the promise returns to.
I want to know if there is a better way to do this or if I am doing something wrong here or if this is the only acceptable way. How do I get angular to hand-off to the MVC action method and let further redirects continue from there only?
You should not use the .success() / .error() pattern with $http, because this has been deprecated. Instead, use then() with two arguments, the first argument being the success function and the second being the error function.
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
You do not need to promisify the result of $http, because $http returns a promise. Just return $http from your service.
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
return $http({
method: 'POST',
url: url,
data: postData,
config: conf
});
}
return service;
});
Your Page A controller will work the same as before with this new simplified code. At the server, be sure to emit a 500 http status code in cases where you want to trigger the
function() {
//on error
window.location = 'http://localhost:1234/home/B';
}
to run. The 500 in the headers of the response will cause the AngularJS promise to run the second function in your controller.

Unable to create POST request to REST API with $resource in angularjs

I am learning about the MEAN stack, and have created a REST API which posts a review to a collection in MongoDB.
I have defined a service as given:
angular.module('myApp')
.constant('baseURL', 'http://localhost:8080/');
angular.module('myApp')
.service('addReviews', ['$resource', 'baseURL', function($resource, baseURL) {
this.getReviews = function() {
return $resource(baseURL+'reviews/', null, {'save': {method: 'POST'}});
};
}]);
Now, I am calling this service from my controller:
angular.module('myApp', ['ngResource'])
.controller('reviewController', ['$scope', 'addReviews', function($scope, addReviews) {
$scope.reviewSubmit = function() {
$scope.receivedReviews = false;
var review = {
// some data
};
$scope.reviews = addReviews.getReviews().query(
function(response) {
$scope.reviews = response;
$scope.receivedReviews = true;
},
function(response) {
$scope.reviews = response;
// print error message
}
);
console.log($scope.reviews); // showing empty array
};
}]);
In routes.js, I have configured my route as:
var Reviews = require('./models/reviews');
...
app.post('/reviews', function(req, res) {
Reviews.create(req.body, function(err, post) {
if (err) {
return res.send(err);
}
return res.json(post);
});
});
I am trying to post a new review to the Reviews collection. However, $scope.reviews is showing an empty array. I logged the requests, and it shows a GET request is being to /reviews instead of POST. I think I should use save() instead of query(), but I have seen some tutorials online where they used query() despite the method being PUT/POST in the service. I am really confused. Can anyone point out how I can post the data (in var review) to the Reviews collection?
There are some issues with your code on the angular side of things.
You want to use $resource as an all-purpose object to communicate with the API. It has built-in functionality to:
query: get all resources from a given API endpoint
get: a single resource, usually by specifying that resource's id
save: post, with an object sent across in the body of the request. NOTE: you don't need the {'save': {method: 'POST'}} in your $resource configuration, you get it for free.
remove and delete: self-explanatory
So you'd want to set up your reviews factory (incl. url constant) like:
angular.module('myApp', ['ngResource'])
.constant('baseURL', 'http://localhost:8080/')
.factory('Reviews', ['$resource', 'baseURL', function($resource, baseURL) {
return $resource(baseURL+'reviews/:id', {id: '#id'});
}]);
If you want to have access to all saved reviews in your controller, as $scope.reviews, you'd do something like:
angular.module('myApp')
.controller('reviewController', ['$scope', 'Reviews', function($scope, Reviews) {
// hit API endpoint to get all reviews
// will have to have app.get('/reviews', function(req, res) {...})
// configured in your node code
Reviews.query(function(data) {
$scope.reviews = data;
}, function(error) {
console.log(error);
});
// and if you want to take a user-written review, say $scope.userReview,
// from the view and save it to the database on click function submitReview()...
$scope.userReview = {
message: '',
createdTime: null
};
// ^ not sure what your ReviewSchema looks like on the backend, but for example...
$scope.submitReview = function() {
if ($scope.userReview.message.length) {
$scope.userReview.createdTime = Date.now();
Reviews.save($scope.userReview);
// ^ this will make POST request with the $scope.userReview object as the request body
}
};
}]);
The create method on your back end looks fine. The object (or maybe just string) you send across will have to match your review schema. You may want to log the request body to make sure you're getting what you expect.
Have a look at this short post on using $resource to interact with RESTful APIs, and (the slightly more confusing) angular $resource docs, for more information on the $resource service.
Hope this helps you!

Using [] square brackets as part of a parameter in $resource GET call to API in Angular is not working

I am trying trying to GET user data from an ajax-localized REST api that wants parameters like so:
/api/activity?filter[user_id]=1
I have a factory set up with query parameters like so:
angular.module('app')
.factory('Activity',function($resource){
return $resource(ajaxInfo.api_url+'activity',
{ // Query parameters
filter: {
'[user_id]': '#userId'
},
},
{
'query':{
method:'GET',
headers: {
'X-WP-Nonce': ajaxInfo.nonce
},
isArray: false
}
});
})
I'm console.logging it in a template like so:
$scope.userOne = Activity.query({userId:1});
console.log($scope.userOne)
It's returning
http:site.dev/api/activity?filter=%7B%22%5Buser_id%5D%22:%22#userId%22%7D&userId=1".
Any idea what I'm doing wrong?
Here's what I did to fix this:
I created a factory called "CurrentUser" this factory basically returns the current user's object from an api.
Then I created a controller that passed the parameters to the Activity factory when I wanted to filter the activity by that user id.
$scope.userInfo = function(){
//call the CurrentUser and see if it's available and return it as u
CurrentUser.instance().then(function(u) {
//now query the activity factory and pass the filter as a string along with the user id as u.id
Activity.query({'filter[user_id]':u.id}, function(res){
$scope.userOne = res ;
console.log($scope.userOne);
});
})
};
$scope.userInfo();

AngularJS : Service for data between controllers

I have a page with a main controller and a nested controller for showing details about a product. I want to use a a service in angular to call the server, retrieve a data object and hold that data object. The main controller will call the service to fetch the data and the details controller needs to know it was updated and then access the data. My service looks like this:
.service("productService", function ($http, $q) {
var product = {};
//interface that is returned
return ({
fetchProduct: fetchProduct,
clearProduct: clearProduct,
product: product
});
function fetchProduct(ID) {
var request = $http({
method: "get",
url: "/online/productdata.ashx?itemID=" + ID,
params: {
action: "get"
}
});
return (request.then(handleSuccess, handleError));
};
function clearProduct() {
product = {};
};
// Transform the error response, unwrapping the application dta from
// the API response payload.
function handleError(response) {
// The API response from the server should be returned in a
// nomralized format. However, if the request was not handled by the
// server (or what not handles properly - ex. server error), then we
// may have to normalize it on our end, as best we can.
if (
!angular.isObject(response.data) ||
!response.data.message
) {
return ($q.reject("An unknown error occurred."));
}
// Otherwise, use expected error message.
return ($q.reject(response.data.message));
};
// I attempt to transform the successful response and unwrap the application data
// from the API response payload.
function handleSuccess(response) {
product = response.data;
console.log("Found Data: " + angular.toJson(response.data))
return (response.data);
};
})
In my main controller I set a scope object to the service like this:
$scope.SelectedProduct = productService;
When the user clicks the button to show the product it is called via the $scope handle:
$scope.SelectedProduct.fetchProduct(ID);
The details controller has the same assignment for the $scope.SelectedProduct. I am new to using services but what I understood is that angular would bind to the service object and changes to the property product would trigger binding to any updates. That is not happening - in fact I do see the data after the fetch operation. In the service I have a console.log on the returned data and it is showing the correct data. However the product property is not getting updated. Can someone tell me what I am doing wrong please? Neither controller has access to the data after it is fetched. I understand that I am getting back a promise but the data is never there even after a timeout check.
Try it with a factory instead of a service.
AngularJS: Factory vs Service vs Provider

Resources