AngularJS Service: can't access child property - angularjs

I have created a service to get the details of a user once he logs in so I can feed this to all my angular controllers:
var app = angular.module('myApp', ['ui.calendar', 'ui.bootstrap']);
app.service('authUser', ['$http', function ($http) {
var _currentUser = {};
$http.get("/Home/GetUser", {
cache: false
}).success(function (data) {
_currentUser.userid = data.userId;
_currentUser.role = data.userRole;
_currentUser.departmentid = data.departmentId;
_currentUser.department = data.userDepartment;
});
this.currentUser = _currentUser;
}]);
app.controller('eventController', ['$scope', 'authUser', '$http', 'uiCalendarConfig', '$uibModal', function ($scope, authUser, $http, uiCalendarConfig, $uibModal) {
$scope.currentUser = authUser.currentUser;
When I try to display the output, it looks alright:
<div>
<label>{{currentUser}}</label>
<label>Id: {{currentUser.userid}}, Role: {{currentUser.role}}, Department Id: {{currentUser.departmentid}}, Department Name: {{currentUser.department}}</label>
</div>
This outputs:
{"userid":"29aa607a-d36b-46bb-a3a7-16bead5f4706","role":"Super
Admin","departmentid":1,"department":"MIS"} Id: 29aa607a-d36b-46bb-a3a7-16bead5f4706, Role: Super Admin, Department Id: 1, Department Name: MIS
But when I try to use the properties of currentUser in my code, nothing is being passed. Example:
$http.get("/Home/GetVenues", {
cache: false,
params: {
currentdepartment: $scope.currentUser.departmentid
}
}).success(function (data) {
// ...
})
I tried
$scope.currentdept = $scope.currentUser.departmentid;
Or
$scope.currentdept = authUser.currentUser.departmentid;
But both of these returns nothing ;m;
I'm apologize if I'm missing something really simple here, but I'm a potato please have mercy ;m;
If it is related at all here is my GetUser method from my HomeController:
public JsonResult GetUser()
{
if (Request.IsAuthenticated)
{
ApplicationDbContext db = new ApplicationDbContext();
var user = db.Users.Find(User.Identity.GetUserId());
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(ApplicationDbContext.Create()));
string id = userManager.FindById(User.Identity.GetUserId()).Id;
IList<string> roleNames = userManager.GetRoles(id);
ReservationsDatabaseModel dept = new ReservationsDatabaseModel();
Department department = dept.Departments.Find(user.DepartmentID);
userDepartmentRole user_department_role = new userDepartmentRole();
user_department_role.userId = user.Id;
user_department_role.departmentId = user.DepartmentID;
user_department_role.userDepartment = department.Name;
user_department_role.userRole = roleNames.FirstOrDefault();
return new JsonResult { Data = user_department_role, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
{
userDepartmentRole user_department_role = new userDepartmentRole();
user_department_role.userId = "0";
user_department_role.departmentId = 0;
user_department_role.userDepartment = "0";
user_department_role.userRole = "Guest";
return new JsonResult { Data = user_department_role, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
}

The fetch of /Home/GetVenues needs to wait for the authUser data to arrive from the server.
Change the service to save a promise:
app.service('authUser', ['$http', function ($http) {
var _ = this;
this.currentUser = {};
this.currentUserPromise = $http.get("/Home/GetUser", {
cache: false
}).then(function (response) {
var data = response.data;
_.currentUser.userid = data.userId;
_.currentUser.role = data.userRole;
_.currentUser.departmentid = data.departmentId;
_.currentUser.department = data.userDepartment;
return data;
});
}]);
Then use that promise in the controller:
authUser.currentUserPromise.then(function(userData) {
$http.get("/Home/GetVenues", {
cache: false,
params: {
currentdepartment: userData.departmentid
}
}).then(function (response) {
var data = response.data;
// ...
})
});
This way the controller waits for the authData to arrive from the server before fetching from /Home/GetVenues.

Your call should work only after GetUser API is returned, you can test by putting GetVenues call on a button click rather than running on init.

Related

How to load data from a factory service before using in application

This is an ASP.NET MVC app with AngularJS.
When the application loads, we have to call some action method which returns a dictionary of resources, string key string value.
This array/dictionary of resources, needs to be available throughout the application.
How can we wait until these resources are loaded before accessing them within the application?
var app = angular.module("app", []);
app.controller("TestCtrl", ['cacheService', function (cacheService) {
var self = this;
self.test = function () {
var value = cacheService.getResourceValue('Err_lbl_UserExist');
}
}]);
app.factory('cacheService', ['$http', function ($http) {
var obj = {};
obj.resourceDictionary = [];
obj.loadResourceDictionary = function () {
var httpConfig = {
url: "/Cache/GetResourceDictionary",
method: "GET",
headers: {
"X-Requested-With": 'XMLHttpRequest',
"__RequestVerificationToken": $("[name=__RequestVerificationToken]").val()
}
}
$http(httpConfig)
.success(function (data) {
obj.resourceDictionary = data;
});
}
obj.getResourceValue = function (resourceKeyName) {
if (obj.resourceDictionary.length <= 0) {
obj.loadResourceDictionary();
}
return obj.resourceDictionary[resourceKeyName];
}
return obj;
}]);
EDIT w/ Accepted Answer
var app = angular.module("app", []);
app.controller("TestCtrl", ['cacheService', function (cacheService) {
var self = this;
self.test = function () {
var value = cacheService.getResourceValue('Err_lbl_UserExist');
}
}]);
app.factory('cacheService', ['$rootScope', '$http', function ($rootScope, $http, $q) {
var obj = { resourcesLoaded: false };
obj.loadResourceDictionary = function () {
obj.resourcesLoaded = false;
var httpConfig = {
url: "Cache/GetResourceDictionary",
method: "GET",
headers: {
"X-Requested-With": 'XMLHttpRequest',
"__RequestVerificationToken": $("[name=__RequestVerificationToken]").val()
}
}
$http(httpConfig).success(function (data) {
obj.resourceDictionary = data;
obj.resourcesLoaded = true;
$rootScope.$broadcast("ResourcesLoaded", null);
});
}
obj.getResourceValue = function (resourceKeyName) {
if (!obj.resourcesLoaded) {
obj.loadResourceDictionary();
$rootScope.$on("ResourcesLoaded", function () {
return obj.resourceDictionary[resourceKeyName];
});
} else {
return obj.resourceDictionary[resourceKeyName];
}
}
return obj;
}]);
you could use broadcast and on for that.
So once your keys are loaded you fire an event using broadcast
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$broadcast
you listen for that message wherever you need to using on :
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$on
you can store the data in a service, this will make it a singleton and you can reuse it, all you have to do is inject the service in whatever controller you need.

Retrieving data from promise | Angularjs

I'm trying to add a top posted section on my dashboard. Getting the top 'captures' aka posts wasn't an issue, though working with Auth0, I need to link the user info with the corresponding users.
Currently I am getting a promise in my dataObj that I pass along to check who made the most votes, but seeing it's asynch I'm having issues retrieving the data and putting it into the users variable:
app.controller('dashboardCtrl', ['$scope', '$http', 'captureApi', 'userApi', 'filterFilter', '$q', function($scope, $http, captureApi, userApi, filterFilter, $q){
$scope.captures = [];
$scope.pageSize = 4;
$scope.currentPage = 1;
$scope.topPosters = [];
captureApi.getAllCaptures().then(function(res) {
$scope.captures = res.data;
userApi.getUsers().then(function(res){
$scope.getCount = function getCount(strCat){
return filterFilter( $scope.captures, {userId:strCat}).length;
};
var users = res.data.users;
var i;
for(i=0; i<users.length; i++) {
var userId = users[i].user_id;
console.log(userId);
console.log($scope.getCount(userId));
$scope.user = userApi.getUser(userId).then(function(res){
$scope.userInfo = res.data;
console.log($scope.userInfo);
return res.data;
});
var dataObj = {
user : $scope.user,
userId : userId,
amountPosted : $scope.getCount(userId)
};
$scope.topPosters.push(dataObj);
}
console.log($scope.topPosters[0].user);
});
});
}]);
As you can see, I get all the captures, then I count them depending on their userId.
Once this is done I add them to the dataObj.
But in between I'm trying to add the user information (using userApi.getUser(ID) and also add their information to this dataObj. At the moment I'm getting a promise. How do I convert this into the dataObj of each user.
Try to load all data before pushing to topPosters. An example:
app.controller('dashboardCtrl', ['$scope', '$http', 'captureApi', 'userApi', 'filterFilter', '$q', function ($scope, $http, captureApi, userApi, filterFilter, $q) {
$scope.captures = [];
$scope.pageSize = 4;
$scope.currentPage = 1;
$scope.topPosters = [];
$scope.getCount = function getCount(strCat) {
return filterFilter($scope.captures, {userId: strCat}).length;
};
$q.all({captures: getAllCaptures(), users: getUsers()}).then(function(collections) {
$scope.captures = collections.captures;
return collections.users;
}).then(function (users) {
return $q.all(users.map(function (user) {
return getUserById(user.userId);
}));
}).then(function (users) {
$scope.topPosters = users.map(function(user) {
//I think your user has propery "id" or similar
return {
user: user,
userId: user.id,
amountPosted: $scope.getCount(user.id)
}
});
console.log($scope.topPosters);
});
function getAllCaptures() {
return captureApi.getAllCaptures().then(function (res) {
return res.data;
});
}
function getUsers() {
return userApi.getUsers().then(function (res) {
return res.data.users;
});
}
function getUserById(userId) {
return userApi.getUser(userId).then(function (res) {
return res.data;
});
}
}]);

AngularJs global service

I'm trying to store a response variable in a global service variable. This is my service:
(function() {
angular.module('employeeApp')
.service('constants',constants);
function constants() {
this.url = 'http://domain.dev/api/v1/';
this.role = '',
this.companyid = '',
this.name = ''
}
})();
loginFactory:
factory.login = function(email,password)
{
var vm = this;
vm.companyid = constants.companyid;
data = {"email": email, "password": password};
requestFactory.post(GLOBALS.url + 'login', data)
.then(function (response) {
vm.role = response.data.result.Employee.Role;
vm.companyid = response.data.result.Employee.CompanyId;
factory.setToken(response.data.result.Employee.api_token);
$cookieStore.put('employeeid', response.data.result.Employee.EmployeeId);
$location.path('/home');
}, function () {
console.log('Niet ingelogd!');
});
}
When I try to access companyid in my homecontroller it's empty. What am I doing wrong. Looking for hours right now but can't find a solution!
You need to inject the constants service into your loginFactory.
https://docs.angularjs.org/guide/di
.factory('loginFactory', ['constants', function(constants) {
Also, you're not returning an object in your constants service
Hey you need to inject the your service as a dependency to you factory
angular.module('employeeApp')
.factory('loginFactory', ['constants', function(constants, $scope) {
$scope.login = function(email,password)
{
var vm = this;
vm.companyid = constants.companyid;
data = {"email": email, "password": password};
requestFactory.post(GLOBALS.url + 'login', data)
.then(function (response) {
vm.role = response.data.result.Employee.Role;
vm.companyid = response.data.result.Employee.CompanyId;
factory.setToken(response.data.result.Employee.api_token);
$cookieStore.put('employeeid', response.data.result.Employee.EmployeeId);
$location.path('/home');
}, function () {
console.log('Niet ingelogd!');
});
}
}
This should work unless there are problems in other parts of your app. Notice semi-colons instead of brackets in function constant and square brackets added to module declaration.
(function() {
angular.module('employeeApp', [])
.service('constants',constants);
function constants() {
this.url = 'http://domain.dev/api/v1/';
this.role = '';
this.companyid = '';
this.name = '';
}
})();
See Fiddle

How to I refresh a JSON object, so it is not too long

org.springframework.http.converter.HTTPMEssageNotReadableException: Could not read JSON: Unexpected end-of-input in VALUE_STRING>
I believe my JSON object may be too long. It has 60 different id's. I want to delete them all, and start a fresh. I used angualrjs $http.put to get them there. I am using angularjs with a ModelSvc. I do not see the id listed in the data.
While bankInfoes/(id) returns the data, but localhost:9001/bankInfoes does not return any data.
This is the angularjs that I use to control the view.
timetrackingServices.factory('BankInfoSvc', ['$resource', '$rootScope', 'RootUrlSvc', 'ModelSvc', '$http',
function ($resource, $rootScope, RootUrlSvc, ModelSvc, $http) {
var initializeModel = function (bankInfo) {
var bankInfoResource = $resource(RootUrlSvc.rootUrls.bankInfoes + ':bankInfoId', {}, {
query: {method: 'GET', isArray: false}
});
bankInfoResource.query(function (data) {
var bankInfoes = data;
ModelSvc.model.bankInfoes = bankInfoes;
});
};
return {
initializeModel: initializeModel
};
}
]);
timetrackingServices.factory('ModelSvc', [
function () {
var model = {};
model.company = {};
model.bankinfoes = {};
model.printBossResponses = {};
model.config = {};
var isCompanyInitialized = function () {
return !angular.equals({}, model.company)
};
var isBankInfoInitialized = function () {
return !angular.equals({}, model.bankInfo)
};
var isPrintBossResponsesInitialized = function () {
return !angular.equals({}, model.printBossResponse)
};
return {
model: model,
isCompanyInitialized: isCompanyInitialized,
isBankInfoInitialized : isBankInfoInitialized,
isPrintBossResponsesInitialized : isPrintBossResponsesInitialized
}
}]);
#RequestMapping(value="/billPaymentOuts", method=RequestMethod.GET)
public List<BillPaymentOut> displayBillPaymentOutPage() {
...
return lList;
}

How can i return my firebase-data to $scope using resolve

There is a service I use to get data from firebase:
'use strict';
angular.module('flbi.services.trainings', [])
.factory('trainingsService', ['FBURL',
function(FBURL) {
return {
getList: function() {
var queryLimit = 10;
var firebase = new Firebase(FBURL);
firebase.child('trainings').limit(queryLimit).on('value', function(trainings) {
var allTrainings = trainings.val();
$.each(allTrainings, function(training) {
firebase.child('users/' + allTrainings[training].userid).on('value', function(user) {
allTrainings[training].user = user.val();
allTrainings[training].user.gravatar = MD5(allTrainings[training].user.email);
});
});
});
}
};
}]);
The function getList() is called from:
$routeProvider
.when('/', {
controller: 'trainingsCtrl',
templateUrl: 'views/default.html',
resolve: {
"trainings": function(trainingsService) {
return trainingsService.getList();
}
}
})
And the controller:
'use strict';
angular.module('flbi.controllers.trainings', ['flbi.services.trainings'])
.controller('trainingsCtrl', ['$scope', 'trainings',
function($scope, trainings) {
console.log(trainings); <-- just empty ....
$scope.trainings = trainings;
}]);
How can I return the data of allTrainings to my controller? I always get an empty Object. But if I check console.log(allTrainings) inner the on()-method of the service, it is full of data...
You resolve method must return a promise in order for this to work as expected. So your getList method should return a promise.
Also, prefer snapshot.forEach() to using .val() as this is highly optimized (it iterates the pointers rather than parsing and collecting all the data into an object and it also sorts the records to match the data, since JavaScript objects are inherently unordered).
angular.module('flbi.services.trainings', [])
.factory('trainingsService', ['FBURL', '$q',
function(FBURL, $q) {
return {
getList: function() {
var def = $q.defer();
var queryLimit = 10;
var firebase = new Firebase(FBURL);
firebase.child('trainings').limit(queryLimit).on('value', function(trainings) {
var promises = [];
var allTrainings = {};
trainings.forEach(function(ss) {
var key = ss.name();
var d = $q.defer();
promises.push(d.promise);
// put any other data you need in the trainings keys here
// allTrainings[key].widget = ss.child('widget').val();
firebase.child('users/' + allTrainings[key].userid).on('value', function(user) {
allTrainings[key].user = user.val();
var email = user.child('email').val();
allTrainings[key].user.gravatar = MD5(email);
d.resolve();
}, d.reject);
$q.when(promises).then(function() {
def.resolve(allTrainings);
}, def.reject);
});
}, def.reject);
return def.promise;
}
};
}
]);

Resources