Using $resource in AngularJS and getting an undefined response - angularjs

I have the following code:
vm.getTheSector = function () {
SectorDataFactory.get({action:'getSector', sectorName:vm.selected}, function (response) {
vm.industry.sector = response.theSector;
});
vm.saveTheIndustry()
};
vm.saveTheIndustry = function () {
SectorDataFactory.save({action: 'saveIndustry'}, vm.industry, function (response) {
vm.responseMessage = response.theMessage;
});
};
I am getting a sector object from a RESTful web service however vm.industry.sector is undefined. I'm trying to then POST the industry object however the sector is null.

vm.getTheSector = function () {
SectorDataFactory.get({action: 'getSector', sectorName: vm.selected}, function (response) {
vm.industry.sector = response.theSector;
vm.saveTheIndustry()
});
};
Thanks to mbeso. The vm.saveTheIndustry() now executes as part of the success callback.

Related

Angular ng-table loading from server with pagination

I am trying to figure out how to populate an ng-table and apply the total value for the params. It appears there are examples that are showing almost what I'm doing - but not exactly and the total never gets set.
$scope.tableParams = new NgTableParams({page: 1, count: 25},
{
counts: [],
getData: function(params)
if (CompaniesView.ViewInitialized)
return CompaniesView.RetrieveCompanies($scope, $http, function ()
{
params.total($scope.RequestFilter.TotalCompanies);
return $scope.TableParams.data;
});
}
});
My RetrieveCompanies function retrieves he data - and will call a callback function on completion. I was under the impression at this point I could set the params.total, but is not working. I see that examples are doing similar, except they are performing a jQuery API operation directly. I am not sure why this does not work. I would have thought anytime setting the total would cause the table pagination controls to update - but it appears it has to be done within the detData call. But if you are making an async call how can we have the total set in the call since it won't have data until the async completes - which means the
getData call has already finished.
Probably missing some concept here -- but I am not an expert when it comes to jQuery or angular.
Peter
Update:
RetrieveCompanies function
RetrieveCompanies: function (scope, http,callback)
{
scope.IsLoading = true;
var Data =
{
AuthoirzationType: TokenRetrieval.SessionAuth,
SessionId: activeSession
};
var tokenRequest =
{
params: Data
};
performVeilabilityTokenRetrieval(http, tokenRequest,
function (response)
{
if (true)
{
if (!response.HasError)
{
scope.RequestFilter.State = scope.selectedState.Value
scope.RequestFilter.regionsearch = scope.selectedRegion.id;
scope.RequestFilter.checkadminStaff = scope.selectedAdmin.value;
//tableParams
scope.RequestFilter.Page = scope.tableParams.page();
scope.RequestFilter.PageCount = scope.tableParams.count();
var config =
{
headers:
{
Authorization: 'Bearer ' + response.RequestToken
},
params: scope.RequestFilter
}
http.get(CompaniesView.Companies_api_urls.loadCompaniesRequest, config)
.then(
function (response)
{
scope.RequestFilter.TotalCompanies = response.data.companieslistTotal;
scope.TableParams.data = response.data.companies;
if (callback != null) callback();
},
function (data, status, headers, config) //error
{
scope.IsLoading = false;
}
);
}
else
{
scope.request.requestToken = null;
//CreateExpenseView.PrepareRESTResults(data.RestResults);
}
}
else
{
scope.request.requestToken = null;
scope.request.error = data.replace(/\"/g, "");
}
});
}
Ok; finally found what was wrong. The ng-table getData operation requires a promise to be returned. My function was not configured as a deferred promise and once I realized this I put in place the required modification for my data retrieval to return a promise. One big point -- when I wrapped my call with a when - I completed with a done - and getData is operating off a then (from the promise). Once those changes were in place the pagination (total) operation worked.
Peter

I set the service data,but after $http done, I cannot get the service data

My service define like this:
module.factory('portfolio',function(){
var data;
var selectedPort;
return{
getData: function(){
return data;
},
setData:function(portfolios){
data = portfolios;
},
getSelectedPort:function(){
return selectedPort;
},
setSelectedPort:function(portfolioDetail){
selectedPort = portfolioDetail;
}
}
});
And in my controller the code as follows:
module.controller('portfoliosController', function($scope,$http, alertService,stockService, userDataService, portfolio){
var req = {
method: 'get',
url: 'www.facebook.com',
headers: {
'Authorization': userDataService.getToken()
}
};
$http(req).then(function(reponse){
$scope.portfoliosPriceList = reponse['data'];
portfolio.setData($scope.portfoliosPriceList);
console.log(portfolio.getData())//At here,I can get the portfolio's data
}, function(){
alertService.setMessge("System maintenance , please try again later");
alertService.alert();
});
console.log(portfolio.getData())//At here, I cannot get the portfolio's data
});
the error is
Error: undefined is not an object (evaluating 'message.substr')
Anybody can help me to solve this problem?Actually, I really do not understand, why I cannot get the data outside the $http
The request that you do with the $http service is done asynchronously, so the callback that you pass to the .send is not immediately invoked.
The code that follows (the console.log) is executed just after the $http(req) call is made but before the callback is called when the request is responded.
Maybe you will understand better with an simpler example:
function portfoliosController() {
var data = 'Initial Data. ',
content = document.getElementById('content');
// setTimeout would be your $http.send(req)
// calledLater would be your .then(function() { ... })
setTimeout(function calledLater() {
data = 'Data coming from the server takes some time to arrive...';
content.innerHTML = content.innerHTML + data;
}, 1000);
content.innerHTML = content.innerHTML + data;
}
portfoliosController();
<div id="content">
This is because javascript is asynchronous, so the code:
portfolio.getData()
Is maybe executing before the data is returned from the service.
In this case, you should only use the data of the portfolio just after the request is complete (inside the .then() function of $http) or put a promise.
Here is the documentation for angular promises:
https://docs.angularjs.org/api/ng/service/$q

AngularJS Service Test (Jasmine/Karma) - Error: Unexpected request: GET

I'm currently trying to test an AngularJS service I've written using Karma and Jasmine. However, I'm currently running into an issue with $httpBackend and I cannot get around it. Here's my service and test:
Service:
export default angular.module("api:events", [])
.factory("Events", ($http) => {
let api = "http://localhost:5000/api/";
let Events = {};
Events.query = (params) => {
return $http.get(`${api}/events`, {params: params}).then((res) => {
return res.data;
});
};
Events.get = (params) => {
return $http.get(`${api}/events/` + params.id).then((res) => {
return res.data;
});
};
return Events;
});
Test:
describe("api:events", () => {
let EventsFactory, $scope, http;
beforeEach(module("app"));
beforeEach(inject((_Events_, $rootScope, $httpBackend) => {
EventsFactory = _Events_;
$scope = $rootScope.$new();
http = $httpBackend;
}));
it("should return an object", () => {
let data = {};
let url = "http://localhost:5000/api/events/:id";
let response = { id: "12345" };
http.whenGET(url).respond(200, response);
data = EventsFactory.get({ id: "1"});
expect(data).not.toEqual("12345");
http.flush();
expect(data).toEqual("12345");
http.verifyNoOutstandingExpectation();
http.verifyNoOutstandingRequest();
});
});
And the error I'm receiving (due to http.flush()):
Chrome 46.0.2490 (Mac OS X 10.10.5) api:events test FAILED
Error: Unexpected request: GET http://localhost:5000/api/events/1
No more request expected
If I log data after data = EventsFactory.get({ id: "1"}); I get Object{$$state: Object{status: 0}}.
I've also tried calling my service like this with similar results:
EventsFactory.get({ id: "1"}).then((result) => {
data = result;
});
Any thoughts?
The problem here is that URLs given to the whenXXX() and expectXXX() methods of the $http mocks have to be literal. One could intuitevely expect that URLs with parameters (e.g. the :id in the code from the question) will work, but that is not the case. So to correct the error, just replace:
let url = "http://localhost:5000/api/events/:id";
with:
let url = "http://localhost:5000/api/events/1"; // `1` is the literal id
Check out the documentation for verifyNoOutstandingExpectation() and verifyNoOutstandingRequest().
It says:
Verifies that all of the requests defined via the expect api were made.
The key words there are "expect api". You are not using the "expect" API, you're using then "when" API. You shouldn't be calling either of these methods at the end of your test when using the "when" API.
The documentation describes the differences between the "expect" and "when" API.

Not returning Restangular back-end call correctly

My back-end call is returning undefined. A.k.a TypeError: Cannot read property 'then' of undefined. I think I am calling it incorrectly.
Here is the AngularJS controller code:
$scope.addUser = function (chaseUser) {
Accounts.addChaseUser(userToSubmit).then(function (response, err) {
if (err) {
$scope.errorMessage = "There was an error.";
$log.debug(err);
} else if (response) {
$scope.errorMessage = "It worked.";
$log.debug(response);
} else {
$scope.errorMessage = "No 'response' nor 'err' returned from backend";
}
});
};
How this responds is that if...
(1) I put in correct credentials, I get a response that comes back with all the transaction data but still TypeError: Cannot read property 'then' of undefined in the console.
(2) Input incorrect credentials, I get no error object, response object, or even making it down to the line where I have $scope.errorMessage = "No 'response' nor 'err' returned from backend"; plus, of course, `cannot read property 'then' of undefined.
Corresponding AngularJS service:
return {
addChaseUser: function(credentials) {
return Restangular.one('user').customPOST(credentials, 'addUser');
}
};
On the backend (controller):
module.exports = {
addChaseUser: function (req, res) {
PlaidService.provideCredentialsToMFA(req.body, function (err, mfaRes) {
if (err) {
return res.status(403).json(err);
}
return res.json(mfaRes);
});
},
};
Backend service:
var plaid = require('plaid');
var plaidClient = new plaid.Client('test_id', 'test_secret', plaid.environments.tartan);
module.exports = {
provideCredentialsToMFA: function (credentials, cb) {
Q.fcall(PlaidService.connectUser.bind(this, credentials))
.then(PlaidService.saveUsersAccessToken.bind(this, credentials))
.then(PlaidService.getTransactionData.bind(this, credentials))
.then(function(transactions) {
cb(null, transactions);
},
function(err) {
console.log(err);
cb(err, null);
});
},
}
How am I supposed to be calling this Restangular POST from the AngularJS controller? It should not be returning undefined.
Since you are getting the response from the server side, it means that your server side code and the angular service code is working just fine. :)
The only possibility I can see is that I is wrong with the application of .then() block is that insted of two parameters(i.e., response and err) lets try with only one parameter.
Something like following :
$scope.addUser = function (chaseUser) {
Accounts.addChaseUser(userToSubmit).then(function (response) {
if(response.status == 'error'){
$log.debug('Got error in the response');
}else{
$log.debug('SUCCESS');
}
});
};
I have used .then(function(data)) with only one parameter. That is the only thing I could find :)
Incase you still don't see it, you are missing a few returns in your functions.
addUser: function (req, res) {
return PlaidService.provideCredentialsToMFA(
// ... your code ...
);
},
provideCredentialsToMFA should return the promise
provideCredentialsToMFA: function (credentials, cb) {
return plaidClient.addConnectUser(
// ... Your code ...
);
}
EDIT:
simplifying the working code looks something like this. Notice there are no returns and only callbacks are used:
findChargeById: function (req, res) {
fetchCharge(someParams, someCallBack);
}
fetchCharge: function (chargeId, cb) {
stripe.charges.retrieve(chargeId, anotherCallBack);
}
Your code looks like this. It's similar but the $scope.addUser expects something returned and doesn't use a callback
addUser: function (req, res) {
provideCredentialsToMFA(someParams, someCallBack);
// addUser returns nothing
}
provideCredentialsToMFA: function (credentials, cb) {
plaidClient.addConnectUser(someParams, someCallBack);
// provideCredentialsToMFA returns nothing and it seems plaidClient.addConnectUser returns nothing too
}
$scope.addUser = function (userInfo) {
// Here is the difference with your 'then' call. Accounts.addUser doesn't return anything and takes 2 params
Accounts.addUser(userInfo).then(someCallBack);
};

Is there a way I can pass in arguments to $http as part of an object?

I am using the following call:
$scope.retrieve = function () {
$resource('/api/Test/Retrieve')
.query({
subjectId: $scope.config.subjectId,
examId: $scope.config.examId,
userId: $scope.config.createdById
},
function (result) {
$scope.grid.data = angular.copy(result);
},
function () {
$scope.grid.data = null;
});
};
Is there a way that I could pass in the arguments through an object like this and use an $http call instead of a $resource. Also how could I move the success and error code blocks to there own functions?
Code below should work for posting with data.
$http.post("/api/Test/Retrieve", {
subjectId:$scope.config.subjectId,
examId:$scope.config.examId,
userId:$scope.config.createdById
}).success(
function(res){
//Some success handler here
}).error(
function(res){
//Some error handler here
});
There are lots of details you may want to include, if you need a GET with parameters check out the config parameter and it's properties:
http://docs.angularjs.org/api/ng/service/$http
//Same sample with handler functions moved out for ease of reading etc.
var successFunction = function(res){
}
var errorFunction = function(res) {
}
var params = {
subjectId:$scope.config.subjectId,
examId:$scope.config.examId,
userId:$scope.config.createdById
};
$http.post("/api/Test/Retrieve", params).
success(successFunction).
error(errorFunction);

Resources