I am using express and angular for my app.
Suppose I have the following factory:
angular.module('LiveAPP.factory',[])
.factory('dataFactory', ['$http', dataFactory])
function dataFactory($http){
var dataFactory = {};
dataFactory.checkDb = function(){
return $http({
method: 'GET',
url: '/artistsearch',
data: "Need this data to go to the request body"
})
}
return dataFacory;
}
And on the server side I have:
app.js
app.get('/artistsearch',dbhelpers.checkDbArtist)
dbhelpers.js
exports.checkDbArtist = function(req,res,next){
var newArtist = req.body;
}
For some reason when checkDb is invoked my get request is not passing on data into my req.body in checkDbArtist. My request body evaluates to {}. Anyone have any idea why?
Related
I'm trying to learn ExpressJS and I'm having trouble getting IP address from an Express route to display in the browser via Angular controller.
I'm using 2 Nodejs modules (request-ip and geoip2) to get the IP and then lookup geolocation data for that IP. Then trying to use Angular to display the geolocation data in the browser using an Angular $http get call.
My Express route for the IP:
// get IP address
router.get('/ip', function (req, res, next) {
console.log('requestIP is ' + ip);
// geolocation
geoip2.lookupSimple(ip, function(error, result) {
if (error) {
//return res.status(400).json({error: 'Something happened'});//default
return res.sendStatus(400).json({error: 'Something happened'});
}
else if (result) {
return res.send(result);
}
});
});
And my AngularJS controller code:
function MainController($http) {
var vm = this;
vm.message = 'Hello World';
vm.location = '';
vm.getLocation = function() {
$http({
method: 'GET',
url: 'localhost:8000/ip'
}).then(function (result) {
console.log(result);
return vm.location = result;
});
};
};
The Hello World message displays but not the location...? I can also go to localhost:8000/ip and see the JSON result. The result doesn't appear in Chrome's console either. The result is a json object like this:
{"country":"US","continent":"NA","postal":"98296","city":"Snohomish","location":{"accuracy_radius":20,"latitude":47.8519,"longitude":-122.0921,"metro_code":819,"time_zone":"America/Los_Angeles"},"subdivision":"WA"}
I'm not sure why the Hello Word displays and the location doesn't when it seems that I have everything configured correctly... so obviously I'm doing something wrong that I don't see...?
You have initialised 'vm.location' as a string when in fact it is a JSON object.
vm.location = {};
You need to adjust the url paramater in your request to:
url: '/ip'
As you are sending back JSON from Express.js, you should change your response line to:
return res.json(result);
Do you call vm.getLocation() somewhere in your code after this?
The data you need is under result.data from the response object.
Also in order to display the data in the html you have to specify which property to display from the vm.location object (vm.location.country, vm.location.city etc..).
From angular docs about $http:
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
Is this express js and angular hosted on the same port? If so please replace your
$http({
method: 'GET',
url: 'localhost:8000/ip'
}).then(function (result) {
console.log(result);
return vm.location = result;
});
with
$http({
method: 'GET',
url: '/ip'
}).then(function (result) {
console.log(result);
return vm.location = result;
});
It may be considered as CORS call and you have it probably disabled.
You can also specify second function to then (look code below) and see if error callback is called.
$http({
method: 'GET',
url: '/ip'
}).then(function (result) {
console.log(result);
return vm.location = result;
}, function (error) {
console.log(error);
});
right now my situation is that I have a post request from an Angular module trying to send some data to an URL handled with node.js and Express.
tickets.js:
$http(
{
method: "post",
url: "/ticketDetail",
headers: {"application/json"},
data: {detail : "test"}
}).then(function successCallback(response)
{
$scope.detail = response.data;
}, function errorCallback(response){});
app.js:
app.post("/ticketDetail", function(req, res)
{
console.log(req.data.detail);
res.json(req.data);
}
It looks like req.data is undefined.
How am I supposed to retrieve the data from my request in my URL handler?
You need to get the data from the body of the req
var qs = require('qs');
app.post('/', function(req,res){
var body = qs.parse(req.body);
var detail = body.detail;
console.log('details',detail); //prints test
});
I believe your post doesn't match the AngularJs syntax. Your $http.post should be like ;
$http.post('/ticketDetail', data, config).then(successCallback, errorCallback);
So for some reason, in your URL handler you are not supposed to access the field data: {detail : "test"} with req.data but with req.body.
app.post("/ticketDetail", function(req, res)
{
console.log(req.body.detail); // prints "test"
res.json(req.data);
}
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.
I have the following service in my Angular App:
myAngularApp.factory('myFactory', function($resource, HOST){
return{
getThings: function(userId, userToken){
var connection = $resource(HOST + '/user/mypost/', {'Userid': userId, 'UserToken': userToken, 'Type': 'Read'}, {
save: {
method: 'POST'
}
});
var results = connection.save();
results.$promise.then(function(data){
results = data;
});
return results;
}
}
});
In one of my controllers, I call the above factory and its function using
myFactory.getThings($scope.someId, $scope.someToken);
When I look at the Network pane in developer tools, the POST request is sent with the correct query string parameters, but the URL is appended with the same parameters (a la GET request). How do I stop the parameters from being appended to my URL?
Try passing your parameters directly to your save() function and remove them from the URL parameters argument in your $resource constructor:
var connection = $resource(HOST + '/user/mypost/', {}, {save: {method: 'POST'}});
var params = {'Userid': userId, 'UserToken': userToken, 'Type': 'Read'};
var results = connection.save(params);
I have a service where I am pulling data from server. When I click the button to send out the request to server through this service, the window freezes until I receive a response from server. Is there anything I can do to make this request asynchronous ?
Here is my service.
app.factory('service', function($http) {
return {
getLogData : function(startTime,endTime){
return $http({
url: baseURL + 'getLogData',
method: 'GET',
async: true,
cache: false,
headers: {'Accept': 'application/json', 'Pragma': 'no-cache'},
params: {'startTime': startTime , 'endTime': endTime}
});
}
};
)};
HTML.
<button ng-click="getData()">Refresh</button>
<img src="pending.gif" ng-show="dataPending" />
Code
$scope.getData = function(){
service.getLogData().success(function(data){
//process data
}).error(function(e){
//show error message
});
}
While there is some argument about the pros and cons of your approach, I am thinking that the problem is answered here: AJAX call freezes browser for a bit while it gets response and executes success
To test if this in fact part of the problem, dummy up a response and serve it statically. I use Fiddler or WireShark to get the response and then save to a file like testService.json. XHR and all of it's various derivatives like $HTTP $.ajax see it as a service though the headers might be slightly different.
Use the success promise, and wrap up the log data in a set of objects that you can attach to a $scope.
So instead of having your service have a blocking method, have it maintain a list of "LogEntries".
// constructor function
var LogEntry = function() {
/*...*/
}
var logEntries = [];
// Non-blocking fetch log data
var getLogData = function() {
return $http({
url : baseURL + 'getLogData',
method : 'GET',
async : true,
cache : false,
headers : { 'Accept' : 'application/json' , 'Pragma':'no-cache'},
params : {'startTime' : startTime , 'endTime' : endTime}
}).success(function(data) {;
// for each log entry in data, populate logEntries
// push(new LogEntry( stuff from data ))...
};
}
Then in your controller, inject your service and reference this service's log data array so Angular will watch it and change the view correctly
$scope.logEntries = mySvc.logEntries;
Then in the HTML, simply do something over logEntries:
<p ng-repeat="logEntry in logEntries">
{{logEntry}}
</p>
use this code to config
$httpProvider.useApplyAsync(true);
var url = //Your URL;
var config = {
async:true
};
var promise= $http.get(url, config);
promise.then(
function (result)
{
return result.data;
},
function (error)
{
return error;
}
);