I'm encountering a weird issue in my AngularJS app. It's supposed to access a number of values from a cookie 'login', pass those values to an API endpoint and then return the API response.
This works fine, except it keeps launching new GET queries continuously every 500ms. This results in an unending stream of the console error: "Error: 10 $digest() iterations reached. Aborting!" and forcing me to kill it manually.
Where is this weird behavior coming from, and how can I limit it to just 1 run?
workbooks.html
<body>
<div>This is the workbooks view.</div>
<span>{{callQueryWorkbooksForUser()}}</span>
<section ui-view>{{response}}</section>
</body>
workbooks.controller.js
'use strict';
(function() {
class WorkbooksComponent {
constructor($scope, $http, $cookies) {
$scope.callQueryWorkbooksForUser = function() {
var login = JSON.parse($cookies.get('login'))
var auth_token = login.authentication_token;
var siteid = login.site_id;
var userid = login.user_id;
$http({
method: 'GET',
url: '/api/sites/' + siteid + '/users/' + userid + '/workbooks',
params: {
auth_token: auth_token
}
}).then(function successCallback(response) {
$scope.response = response.data
}, function errorCallback(response) {
$scope.response = 'Server error'
});
};
}
}
angular.module('orbitApp')
.component('workbooks', {
templateUrl: 'app/workbooks/workbooks.html',
controller: WorkbooksComponent
});
})();
Make the http request in init block of your controller.
class WorkbooksComponent {
constructor($scope, $http, $cookies) {
this.$onInit = function() {
var login = JSON.parse($cookies.get('login'))
var auth_token = login.authentication_token;
var siteid = login.site_id;
var userid = login.user_id;
$http({
method: 'GET',
url: '/api/sites/' + siteid + '/users/' + userid + '/workbooks',
params: {
auth_token: auth_token
}
}).then(function successCallback(response) {
$scope.response = response.data
}, function errorCallback(response) {
$scope.response = 'Server error'
});
};
}
}
Related
i have an error between angularjs controller and $http services
The error is saying that the privileges is not defined. i am trying to post an object to an API
any idea or help, thanks in advance
var userpermissions = angular.module("userpermissions", [])
.service("Permissions", function ($http) {
var urlBase = "/UserPermissionAPI/api";
this.save = function (url) {
return $http({
method: "POST",
url: urlBase + '/' + url,
data: privileges,
async: false,
})
};
})
.controller("userpermission", function ($scope, Permissions) {
$scope.insert = function () {
var promisePost = Permissions.delete("UserPermission/delete?staffkey=" + $scope.staffkey + '&module=' + $scope.modulecd);
promisePost.then(function (pl) {
var privileges = {
Staff_Key: $scope.staffkey, Update_Per: $scope.updates, Save_Per: $scope.saves, Delete_Per: $scope.deletes, Search_Per: $scope.searches,
Add_Admin_User: $scope.staffkeyurl, Module_Code: $scope.modulecd, Report_Per: $scope.reports
};
var promisePost = Permissions.save("UserPermission/save");
promisePost.then(function () {
toastr.success("Successfully saved");
})
}, function (err) {
console.log("Err" + err);
});
}
You are not passing previleges anywhere in your service, change it as
var privileges = {
Staff_Key: $scope.staffkey, Update_Per: $scope.updates, Save_Per: $scope.saves, Delete_Per: $scope.deletes, Search_Per: $scope.searches,
Add_Admin_User: $scope.staffkeyurl, Module_Code: $scope.modulecd, Report_Per: $scope.reports
};
var promisePost = Permissions.save("UserPermission/save", previleges);
and the method inside the service to accept previleges,
this.save = function (url,previleges) {
return $http({
method: "POST",
url: urlBase + '/' + url,
data: privileges,
async: false,
})
};
var promisePost = Permissions.save("UserPermission/save");
This line needs to be changed.
In this line if you send privileges object as a one more parameter and change your save function to accept it, then this will work. Check below.
var promisePost = Permissions.save("UserPermission/save", privileges);
this.save = function (url, privileges) {
return $http({
method: "POST",
url: urlBase + '/' + url,
data: privileges,
async: false,
})
};
I get a value of "True" in my response. How come my debugger and alert and AccessGranted() in the .then of my $http is not being invoked. Below is my Script:
app.controller("LoginController", function($scope, $http) {
$scope.btnText = "Enter";
$scope.message = "";
$scope.login = function() {
$scope.btnText = "Please wait...";
$scope.message = "We're logging you in.";
$http({
method: 'post',
url: '/Login/Login',
data: $scope.LoginUser
}).then(function (response) {
debugger;
alert(response.data);
if (response.data == "True") {
AccessGranted();
} else {
$scope.message = response.data;
$scope.btnText = "Enter";
}
},
function (error) {
$scope.message = 'Sending error: ' + error;
});
}
$scope.AccessGranted = function() {
window.location.pathname("/Home/HomeIndex");
}
});
This is in my HomeController
public ActionResult HomeIndex()
{
var am = new AuditManager();
var auditModel = new AuditModel()
{
AccountId = 0,
ActionDateTime = DateTime.Now,
ActionName = "Home",
ActionResult = "Redirected to Home"
};
am.InsertAudit(auditModel);
return View("Index");
}
Please see image for the response I get.
seems like your approach is wrong
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Try this,
$http({
method: 'post',
url: '/Login/Login',
data: $scope.LoginUser
})
.then(function (response) {
console.log(response);
},
function (error) {
console.log(error);
});
And check your browser console for logs or any errors
Make sure the response is application/json content type, and content is json.
You can also write own httpProvider for check result from server
module.config(['$httpProvider', function ($httpProvider) {
...
I would suggest you to code like this instead of then so whenever there is success, The success part will be invoked.
$http.get('/path/').success(function (data) {
$scope.yourdata = data.data;
//console.log($scope.yourdata);
}).error(function (error){
//error part
});
This question is related to another one.
Before I did added $ionicPlatform, my service working just fine, but now there is something wrong with $http.
Here is example of injectables:
(function () {
"use strict";
angular.module('service', ['ionic'])
.service('BBNService', ["$http", "$localStorage", "$ionicPlatform",
function ($http, $localStorage, $ionicPlatform) {
And using of $http and $ionicPlatform
this.tips = function () {
var url;
$ionicPlatform.ready(function () {
if (window.Connection) {
if (navigator.connection.type == Connection.CELL_4G || navigator.connection.type == Connection.WIFI) {
if (this.getDayId = 0)//If Sunday - retrieve updated tips
url = this.host + "/tips/";
else
url = "data/tips.json";//If not - use saved data
}
}
});
var request = $http({
method: "GET",
url: url
}).then(
function mySucces(response) {
return response.data;
},
function myError(response) {
return response.data;
});
return request;
};
You need to send back the promise, doing a return response.data is not gonna work.
var deferred = $q.defer();
var request = $http({
method: "GET",
url: url
}).then(
function mySucces(response) {
deferred.resolve(response.data);
},
function myError(response) {
deferred.reject(response.data);
});
return deferred.promise;
And at the place where you consume this service:
BBNService.tips().then(
function(data) { //success call back with data },
function(data) { //error call back with data }
);
Please let me know if you need more explanation on using $q; always happy to give more details.
I'm afraid I may have gone down the rabbit hole of recursive promises.
I have a service that handles my api. (It's got an extra layer of promise so that I could switch back to a local json if the api went offline. (Not sure how necessary it is anymore) - mayte I should eliminate it for simplicity).
Then I've got the promised async call in my controller.
This all works great as long as I get the data I expect, but it doesn't handle errors very well. When I get 400's and 500's, it doesn't send the error message to the user via toastr.
Sadly, this is not a fully-compliant RESTful api. The 400 error I get back is simply
{"Message":"No packages found"}
I don't really get how to get this to behave as it should, and replace success/error with then/catch (as per Angular best practice).
Here is a typical service call:
var _getPackagesPage = function (options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $q (function(resolve, reject) {
switch (dataSource) {
case 'api'://staging - live api data
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
}).then(function(results) {
resolve(results);
});
break;
default: // dev - local json
$.getJSON('Content/data/Packages.json', function (json) {
var pageSize = options.data.pageSize;
var page = options.data.page;
var newjson = json.splice(page*pageSize,pageSize);
resolve(newjson);
});
}
});
};
and a typical call in a controller:
(options is the data object handed back to my data grid (Kendo))
vm.getPackages = function(options) {
return packagesService.getPackagesPage (options)
.then(function(results) {
options.success(results.data.Items);
})
.catch(function(error) {
options.error(error);
toastr.error(error.Message);
});
};
How can I clean this up?
[ UPDATE ] Attempted fix per Answer 1, below
Service:
var _getOrdersPage = function (options) {
var deff = $q.defer();
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
})
.then(
function(results) {
deff.resolve(results);
},
function(ex){
deff.reject(ex);
});
return deff.promise;
};
Controller:
vm.getOrders = function (options) {
return ordersService.getOrdersPage (options)
.then(function(results) {
console.log("results!");
console.log(results);
})
.catch(function(error) {
console.log("error!");
console.log(error);
});
};
results in:
GET http://< myURL >/api/Packages?pageSize=20&page=0 400 (Bad Request)
results!
undefined
I'm removing the switch case for brevity.
var _getPackagesPage = function (options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
var deff = $q.defer();
$http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
}).then(
function(results) {
deff.resolve(results);
},
function(ex){
deff.reject(ex);
});
return deff.promise;
};
Controller
vm.getOrders = function (options) {
return ordersService.getOrdersPage (options)
.then(
function(results) {
console.log("results!");
console.log(results);
},
function(error) {
console.log("error!");
console.log(error);
});
};
If you dont have any logic inside your service, then you could return the $http itself as $http inturn is a promise:
var _getPackagesPage = function (options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
});
};
You have too many returns in your service. The second one is not called.
You don't need to create a promise manually since $http returns apromise.
You're not returning data from your service.
var _getOrdersPage = function(options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
})
.then(
function(results) {
return results;
},
function(ex){
return ex;
});
}
Your controller is fine, you can use catch() or pass an error callback.
Example:
function myService($http) {
this.getData = function(url) {
return $http.get(url).
then(function(response) {
return response.data;
}, function(error) {
return error;
});
}
};
function MyController(myService) {
var vm = this;
vm.result = [];
vm.apiUrl = "https://randomuser.me/api/";
myService.getData(vm.apiUrl).then(function (data) {
vm.result = data;
},
function(error) {
console.log(error);
});
};
angular.module('myApp', []);
angular
.module('myApp')
.service('myService', myService)
.controller('MyController', MyController);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController as ctrl">
{{ ctrl.result }}
</div>
</div>
I have tried to build a service that will return a $resource after the service has authenticated.
I have done it like this:
.factory('MoltinApi', ['$q', '$resource', '$http', 'moltin_options', 'moltin_auth', function ($q, $resource, $http, options, authData) {
var api = $resource(options.url + options.version + '/:path', {
path: '#path'
});
var authenticate = function () {
if (!options.publicKey)
return;
var deferred = $q.defer();
var request = {
method: 'POST',
url: options.url + 'oauth/access_token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: "grant_type=implicit&client_id=" + options.publicKey
};
$http(request).success(function (response) {
authData = response;
deferred.resolve(api);
});
return deferred.promise;
};
return authenticate();
}])
But I can not call the resource in my controller:
.controller('HomeController', ['MoltinApi', function (moltin) {
var self = this;
moltin.get({ path: 'categories' }, function (categories) {
console.log(categories);
});
}]);
it just states that 'undefined is not a function'.
Can someone tell me what I am doing wrong?
Update 1
So after playing with the solution that was suggested, this is the outcome.
angular.module('moltin', ['ngCookies'])
// ---
// SERVICES.
// ---
.factory('MoltinApi', ['$cookies', '$q', '$resource', '$http', 'moltin_options', function ($cookies, $q, $resource, $http, options) {
var api = $resource(options.url + options.version + '/:path', {
path: '#path'
});
var authenticate = function () {
if (!options.publicKey)
return;
var deferred = $q.defer();
var authData = angular.fromJson($cookies.authData);
if (!authData) {
console.log('from api');
var request = {
method: 'POST',
url: options.url + 'oauth/access_token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: "grant_type=implicit&client_id=" + options.publicKey
};
deferred.resolve($http(request).success(function (response) {
$cookies.authData = angular.toJson(response);
setHeaders(response.access_token);
}));
} else {
console.log('from cookie');
deferred.resolve(setHeaders(authData.access_token));
}
return deferred.promise;
};
var setHeaders = function (token) {
$http.defaults.headers.common['Authorization'] = 'Bearer ' + token;
}
return authenticate().then(function (response) {
return api;
});
}]);
and to call it I have to do this:
.controller('HomeController', ['MoltinApi', function (moltin) {
var self = this;
moltin.then(function (api) {
api.get({ path: 'categories' }, function (categories) {
console.log(categories);
self.sports = categories.result;
});
});
}]);
but what I would like to do is this:
.controller('HomeController', ['MoltinApi', function (moltin) {
var self = this;
moltin.get({ path: 'categories' }, function (categories) {
console.log(categories);
}, function (error) {
console.log(error);
});
}]);
As you can see, the service is checking to see if we have authenticated before returning the API. Once it has authenticated then the API is returned and the user can then call the api without having to authenticate again.
Can someone help me refactor this service so I can call it without having to moltin.then()?
You are returning the authenticate function call in the MoltinApi factory, so you are returning the promise. And the method get doesn't exist in the promise