Use data from angular to make external api call in node express - angularjs

I am trying to use data that the user inputs to make an api call to an external API using node. I have successfully made calls from the server, and returned them to angular. But I need to send the server a variable from angular, have it make a call, and return the response to my view. I am new to node so I am sorry if this has already been answered somewhere. I looked around and found nothing.
My html
<md-input-container class="md-block" flex-gt-sm>
<label>Player 1</label>
<input ng-model="player1.username">
</md-input-container>
<md-button ng-click="comparePlayers(player1, player2)">COMPARE!</md-button>
My controller function
$scope.comparePlayers = function(player1) {
Nerd.getPlayer(player1)
}
My 'Nerd' Service
smiteStats.factory('Nerd', ['$http', function($http) {
return {
getPlayer: function(playerName) {
$http.post('/api/getPlayer', playerName).success(function(data) {
console.log("sent to server"); //does not run
})
}
}]);
My Express Route
app.post('/api/getPlayer', GetPlayer.apiGetPlayer);
My node module that makes the api call
module.exports = {
apiGetPlayer: function(error, res, player) {
console.log(player); //this returns "[Function: next_layer] in my cmd
}
}

To send Parameters with $http in POST:
$http({
url: host + '/api/getPlayer',
method: "POST",
data: { 'fruit1' : "Apple"}
})
.then(function(response) {
// success
},
function(response) { // optional
// failed
});
To get POST parameters, you will need the ExpressJS body-parser package. This will allow you to grab information from the POST.
Read more

Related

Redirect angular path but hold server data

Sorry if this could be a newbie question.
So this frontend app has an interceptor.
For each request to server, the interceptor will be the first to manage the server response:
service.responseError = function (response) {
};
Now, if the server returns other status then 200, I want to redirect to another frontend path:
service.responseError = function (response) {
if (response.status === 419){
$location.path(handleError);
return;
}
return response;
};
handleError is an angular controller. Can this controller come over the server response?
Ok, doing this in interceptor:
$rootScope.interceptorData = response.data;
And then in controller injecting $rootScope and reading from it, solves it.

Angularjs - How can editable data be shared between run, factory and controller blocks?

tl;dr - app.run resets $rootScope.variable's value every time I invoke an API - I need help finding a way around that.
I have an AngularJS + ASP.NET Web API setup. I need AngularJS to send a token in every API call except login API, I have placed this code in my app.run:
.run(function ($rootScope) {
// $rootScope.token = "" // <-- removed this initialization for now
var sendToken = $rootScope.token == null ? "" : $rootScope.token;
$.ajaxSetup({
headers: {
'myToken': sendToken;
}
});
}
My login API gets the token in its response - I save that value in $rootScope.token and then I want to send that token as a value of 'myToken' in the HTTP header of all other API calls. So loginController should be allowed to update $rootScope and $.ajaxSetup should get updated value of $rootScope.token.
This is how my loginController gets the token value and updates $rootScope.token:
.controller('loginController', function($apiFactory, $rootScope) {
$apiFactory.callAPI(
'/api/login/login',
{'username': 'x', 'password': 'y'},
function(apiResponse) {
$rootScope.token = apiResponse.data;
});
})
$apiFactory.callAPI is a standard function I've made in a factory for the actual API call.
.factory('$apiFactory', function () {
var root = {};
root.callAPI = function (apiName, data, successCB) {
$.ajax({
url: apiName,
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json; charset=utf-8',
}).done(function (apiResponse) {
if (apiResponse.error == false) {
successCB(apiResponse);
}
});
}
return root;
}
LoginController successfully updates $rootScope.token, but when I make the next API call, it goes to .run to run the ajaxSetup, and finds $rootScope.token as undefined.
What should I do to fix this? Thanks a lot!
$rootScope.$broadcast is sending an event through the application scope. Any children scope of that app can catch it using a simple: $scope.$on().
$rootScope.$broadcast("hi");
$rootScope.$on("hi", function(){
//do something
});
.service("hiEventService",function($rootScope) {
this.broadcast = function() {$rootScope.$broadcast("hi")}
this.listen = function(callback) {$rootScope.$on("hi",callback)}
})
We can add\extend default headers in AJAX call.
You need use $http service.
Example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function(ExampleService, AuthService) {
var vm = this;
vm.start = function() {
ExampleService.getData();
};
vm.auth = function() {
AuthService.auth();
}
})
.service('ExampleService', function($http) {
return {
getData: function() {
return $http.get("/urlsource");
}
}
}).service('AuthService', function($http) {
return {
auth: function() {
return $http.get("/auth")
.then(function(apiResponse) {
//after success auth add token
$http.defaults.headers.common['myToken'] = apiResponse.data;
})
.catch(function() {
// just for example in jsfiddle, because we got 404 error for request `auth` url
$http.defaults.headers.common['myToken'] = '12314dsfsfsd';
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController as vm">
<pre>Steps:
1) Press "Start Request" button and check in console header
2) Press "Simulate auth" button. This is add default header "myToken"
3) Press "Start Request" button and check in console header "myToken".
</pre>
<button ng-click="vm.start()">
Start Request
</button>
<button ng-click="vm.auth()">
Simulate auth
</button>
</div>
</div>
Unfortunately, snippet doesn't work. But jsfiddle work fine.

Not able to update data in mongoDB using AngularJs

When I try to change the status of a blog , the status is not updating in database. Status is string field and is initially stored as 0 in database
api.post('/statuschange', function(req, res){
Blog.find({_id: req.query.blog_id}).update({$set:{'status': req.body.status}}, function (err, status) {
if(err){
res.send(err);
return;
}
if(req.body.status == '1') {
res.json('Blog added')
return;
}
if(req.body.status == '-1'){
res.json('Blog not added');
return;
}
});
})
api is working successfully on postman
factory file
angular.module('blogfact', ['authService'])
.factory('blogFactory', function($http, AuthToken){
var factory = {};
var token = AuthToken.getToken();
factory.changestatus = function(info, callback){
$http({
url: 'api/statuschange',
method:'POST',
headers:{'x-access-token':token},
params:{'blog_id': info},
})
.success(function(response){
callback(response)
})
}
return factory
})
the controller file
angular.module('blogCtrl', ['blogfact']);
.controller('BlogController', function(blogFactory, $routeParams){
var that=this;
blogid = $routeParams.id;
var getthatBlog = function(){
blogFactory.getthatBlog(blogid, function(data){
//console.log('[CONTROLLER] That Blog:',data);
that.blog = data;
})
}
this.changestatus = function(info){
blogFactory.changestatus(info, function(data){
getthatBlog();
})
}
})
html file
<div ng-controller="BlogController as blog">
<textarea ng-model="blog.status"></textarea>
<button class="btn btn-success" ng-click="blog.changestatus(blog._id)">Submit</button>
</div>
If your question is regarding the value in MongoDB not being updated, well it seams it is due to the status data missing in your POST request.
I recommend that in your HTML, send the whole blog object so that you have the blog's status as well:
<button class="btn btn-success" ng-click="blog.changestatus(blog)">Submit</button>
Then in your blogFactory add the data as such:
$http({
url: 'api/statuschange',
method:'POST',
headers:{'x-access-token':token},
params:{'blog_id': info._id},
data: {status: info.status} // <==
})
Now, you should be able get the blog status data in NodeJS server back-end via req.body.status.
Update
Try the following with mongoose's update method:
Blog.update({_id: req.query.blog_id}, {status: req.body.status}, function(err, numAffected){
...
});
Or, alternatively:
Blog.findOne({_id: req.query.blog_id}, function(err, blog){
blog.status = req.body.status;
blog.save();
});
Angular let's you modify collection data on the client-side, but to actually update it on your server you need to notify the server of your changes (via API).
There are a few ways to do this, but if you want seamless updating from client-side to server maybe give meteor a try.
http://www.angular-meteor.com/
https://www.meteor.com/
Your are sending the data in params and getting the data from req.body.
You should use req.query or req.param. Else, Send the data on body like below,
$http({
url: 'api/statuschange',
method: 'POST',
params: { 'blog_id': info },
data: { 'status': 1 }
})
Your are passing 1 parameter in client side and getting two parameters on server side(req.body.status, req.query.blog_id)
Where is the token value from ?
Check the simplified way to test your code
http://plnkr.co/edit/tyFDpXw2i0poICwt0ce0

Mocking backend with Protractor

I found a lot of similar discussion about this topic but unfortunately none of them fit my scenario.
I'm trying to mock the backend response from Protractor for testing a new functionality that is not present in the real API at the moment.
I tried different ways for achieving that but with no luck. Every time I run the protractor test, the http request is performed to real API instead of intercepting the request.
Here is my scenario:
I have an AngularJS application and there is a search input box in one view like this:
<input type="text" class="form-control rounded input-lg" placeholder="Search Contacts" ng-model="contactCtrl.filter" ng-change="contactCtrl.inspectFilter()" focus="true" id="inputSearch">
Then, I have a controller for that:
function inspectFilter() {
$q.all([
comService.indexContacts($rootScope.$user.cloudContacts, vm.filter)
.then(function(response) {
vm.contacts = angular.copy(contacts);
})
.catch(function() {
})
]).then(function() {
});
}
}
And the comService.indexContacts that performs the http request:
function indexContacts(url, filter) {
var filtered_url = filter ? url + '?displayName=' + encodeURIComponent(filter) : url;
initializeRequest();
req = {
headers : {
'Authorization' : getAuthenticationToken()
},
method : 'GET',
url : filtered_url
};
return $http(req);
}
I'm not going to explain the logic of everything but let's just say that when the user type something in the input filed, the indexContacts function triggers a GET request to the API and the user can see a list of contacts rendered on the screen.
Now I would very like to intercept that $http(req) in my Protractor test and return a mock JSON back but I don't understand how.
'use strict';
describe('Making a call from the contact detail screen', function() {
beforeAll(function() {
contacts.goToContacts();
element(by.id('inputSearch')).clear().sendKeys('gai');
});
describe('UAT1 - Clicking the number to make a call', function() {
it('Given that the user is on the Cloud contact/user detail screen', function() {
element(by.repeater('contact in contactCtrl.results').row(0)).element(by.css('.tdName')).click();
dom.waitForElementDisplayed(element(by.css('.contact-modal')));
});
...
...
Ok, what I do in here is injecting some text into the search field with: element(by.id('inputSearch')).clear().sendKeys('gai'); and this works, but, I want to intercept the http request triggered by the previous comService and, instead, return a mock JSON back to the application to render a custom list of users instead of using the real API for that.
How can I do that????

MEAN.JS Contact Form

Trying to create a contact form and feedback form for my website. Here is my route and controller I'm using however I need to understand what's going on with my routes and how to capture the input fields from the form implement this inside MEAN.JS:
route.js:
app.route('/mail').get(mail.createmail);
app/controller.js:
exports.createmail = function(req, res) {
var mailOpts, smtpTrans;
// create reusable transporter object using SMTP transport
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'administrator#radleaf.com',
pass: '34Girls34*goo'
}
});
// NB! No need to recreate the transporter object. You can use
// the same transporter object for all e-mails
// setup e-mail data with unicode symbols
var mailOptions = {
from: 'Fred Foo ✔ <foo#blurdybloop.com>', // sender address
to: 'ty#radleaf.com', // list of receivers
subject: 'Hello ✔', // Subject line
text: 'Hello world ✔', // plaintext body
html: '<b>Hello world ✔</b>' // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Message sent: ' + info.response);
}
});
};
Not sure how this work with the HTML with the view:
<form action="mail">...</form>
If I understand the question correctly, you're asking how you can gather data which is input into a form, send that data to expressJS, and then use that data to send an outbound email.
If so, then here is your flow:
Step 1: Create a form in a view and map it to an AngularJS controller
<form name="contactForm" data-ng-submit="sendMail()">
Name: <input type="text" data-ng-model="contact_name">
Message: <input type="text" data-ng-model="contact_msg">
<button type="submit">
</form>
Step 2: In your AngularJS controller, use a $http request to send your data to your Express Route
$scope.sendMail = function() {
// Simple POST request example (passing data) :
$http.post('/mail', {name: contact_name, msg: contact_msg}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
Step 3: Use your ExpressJS Route as an API to call your ExpressJS Controller.
(It looks like you've got this bit covered)
app.route('/mail').get(mail.createmail);
Step 4: Receive and do something with the data passed through the $http POST
exports.createmail = function(req, res) {
var data = req.body;
Now you can use the data, like this
var mailOptions = {
from: data.name, // sender name
text: data.msg, // plaintext body
};
MeanJS 0.4.0 also has a working example of NodeMailer which might help: https://github.com/meanjs/mean/tree/0.4.0
With angularJS, you can remove the action attribute, and just use angularJS ngSubmit directive, and call a function in your controller which would now visit the endpoint with $http.get.

Resources