I have two controllers and one Factory. I am using angular-devise module for authentication.
UserFactory.js
myApp.factory('Userfactory', function(Auth,$location){
var Userfactory = {}
Userfactory.user = []
Userfactory.active = false
Userfactory.isLogged = function(){
if(!Userfactory.active[0]){
return Auth.currentUser().then(function(user) {
Userfactory.user.push(user)
Userfactory.active = angular.copy(true)
}, function(error) {
});
}
}
return Userfactory;
})
UserController.js
myApp.controller("userController",function($scope,Userfactory){
Userfactory.isLogged().then(function(){
$scope.active = Userfactory.active;
})
}
NavController.js
myApp.controller("navController", function navController(Userfactory){
this.user = Userfactory.user;
this.active = Userfactory.active;
})
UserFactory.active in nav controller is not updating when isLogged updates the value , since the value is getting resetted (which breaks binding) , where as in user controller the value is assigned through promise , so its getting the latest value. My doubt is how to manage to get it working in both places, meaning how to assign value without breaking the binding.
One workaround is declaring Userfactory.active as an array and pushing the value to it as true or false, but looking for better way of doing it, any help will be useful.
I would recommend you to use a model Object to wrap all the variables/properties you need to be bindable.
myApp.factory('Userfactory', function(Auth,$location){
var Userfactory = {}
Userfactory.model = {
user: undefined,
active: false
};
Userfactory.isLogged = function(){
if(!Userfactory.active[0]){
return Auth.currentUser().then(function(user) {
Userfactory.model.user = user;
Userfactory.model.active = true;
}, function(error) {
});
}
}
return Userfactory;
})
And then on your controllers:
myApp.controller("userController",function($scope,Userfactory){
Userfactory.isLogged().then(function(){
$scope.userModel = Userfactory.model;
// and on the UI use: userModel.active
})
}
myApp.controller("navController", function navController(Userfactory){
this.userModel = Userfactory.model;
// then access it like: this.userModel.active
})
Related
Right now I am passing my parameter through the state like:
.state('app.listing', {
url: '/ad/listing/:adId/{type}',
params: {
adId: {
value: "adId",
squash: false
}, type: {
value: null,
squash: true
}
},
This works as I can get "type" from $stateParams and update my get request.
Is there not a way to do this from a click event and not use $stateParams for passing the "type" param?
I basically have a button that filters results and passes the type param from the button. It would be a lot easier if I can just attach a click event to it which then updates my get request.
Just messing around I tried doing something like
$scope.filter = function(type) {
if(type) {
return type;
}
return '' ;
}
$scope.type = $scope.filter();
Service is like
$http.get(API_ENDPOINT.url + '/listing/' + adId, {
params: {
page: page,
type: type // essentially $scope.type
},
}).
and then on my button I have
<button ng-click="filter('2')"></button>
^ This will pass 2 for type, but won't reinit the http get call on click. Do I need to broadcast the change is there a simple way to do this?
Does this even make sense? The code above is just mock to give an idea, but open to suggestions if any.
Angular never requires you to make broadcasts to reflect changes made to scopevariables via the controller
var typeWatcher = '1';
$scope.filter = function(type){
if (type !== typeWatch)
{
$http.get(API_ENDPOINT.url + '/listing/' + adId, {
params: {
page: page,
type: type // essentially $scope.type
},
});
typeWatcher = type;
}
};
You can wrap your get call in a function & call it after the filter function in ng-click
$scope.functionName = function () {
return $http.get(API_ENDPOINT.url + '/listing/' + adId, {
params: {
page: page,
type: type // essentially $scope.type
}
})
}
then in HTML
<button ng-click="filter('2'); functionName()"></button>
Well, To call $http.get method on click,
$scope.filter = function(type) {
if(type) {
//call the method using service.methodName
return type;
}
return '' ;
}
and wrap that $http.get method to one function.
Hope it helps you.
Cheers
This function fires once at page load, but then never again. I've tried $watch, $apply, and firebase's ref.on('value', ... but no dice. The model changes for the value of scope.job.getApplicants(), but scope.applicants_ is not refreshing when this happens.
function go() {
var p = [];
// scope.job.getApplicants() returns a $firebaseArray of user IDs
scope.job.getApplicants().$loaded().then(function(list) {
list.forEach(function(app) {
// User_(app.$id) returns a $firebaseObject
var user = User_(app.$id);
p.push(user);
})
});
return p;
}
scope.applicants_ = go();
This is how I resolved the problem:
ref.on('value', function(apps) {
var applicantIDs = Object.keys(apps.val());
scope.applicants_ = applicantIDs.map(function(app) {
return User_(app);
});
});
I am building an SharePoint App using AngularJS and am attempting to define a service that retrieves if the user is an Admin or not. The service itself is successfully logging/working as expected, but I am not sure how to use this in a controller. My end goal is that when a page loads that is tied to a controller, that this service checks if they are an admin or not. From that point, I can do all sorts of magic (ex. redirect, etc.). Here is my service:
// Check if user is an admin
appServices.factory('appAdminCheck', ['$resource', 'appCurrentUserProfile', 'appAdmins', function ($resource, appCurrentUserProfile, appAdmins) {
var userAdmin = [];
appCurrentUserProfile.query(function (usercheck) {
var userID = usercheck.Id;
appAdmins.query(function (admins) {
var admins = admins.value; // Data is within an object of "value", so this pushes the server side array into the $scope array
// Foreach type, push values into types array
angular.forEach(admins, function (adminvalue, adminkey) {
if (adminvalue.Admin_x0020_NameId == userID) {
userAdmin = true;
console.log("I'm an Admin" + userAdmin);
}
});
});
});
return userAdmin;
}]);
Update: Upon closer inspection, I would like to return the array of values, but it keeps stating that the array length is 0. I am sure it is because I am not "returning" properly.
Here is my updated service:
appServices.factory('appAdminCheck', ['$resource', 'appCurrentUserProfile', 'appAdmins', function ($resource, appCurrentUserProfile, appAdmins) {
var userAdmin = [];
var checkUser = function() {
appCurrentUserProfile.query(function (usercheck) {
var userID = usercheck.Id;
appAdmins.query(function (admins) {
var admins = admins.value; // Data is within an object of "value", so this pushes the server side array into the $scope array
// Foreach type, push values into types array
angular.forEach(admins, function (adminvalue, adminkey) {
if (adminvalue.Admin_x0020_NameId == userID) {
userAdmin.push({
isAdmin: 'Yes',
role: adminvalue.Role,
});
}
});
});
});
return userAdmin;
}
return {
checkUser: checkUser
};
}]);
Here is a logging call in a controller:
var test = appAdminCheck.checkUser();
console.log(test);
Seeing as there appears to be some asynchronous actions happening, you'll want to return a promise. You can do this by chaining the then promise resolution callbacks from your other services (assuming they're $resource instances or similar). For example...
appServices.factory('appAdminCheck', function (appCurrentUserProfile, appAdmins) {
return function() {
return appCurrentUserProfile.query().$promise.then(function(usercheck) {
return appAdmins.query().$promise.then(function(admins) {
// this needs to change if admins.value is not an array
for (var i = 0, l = admins.value.length; i < l; i++) {
if (admins.value[i].Admin_x0020_NameId === usercheck.Id) {
return true;
}
}
return false;
});
});
};
});
Then, you can use this promise resolution in your controller, eg
appAdminCheck().then(function(isAdmin) {
// isAdmin is true or false
});
In app.js I have a variable that I use in two files/controllers:
var app = angular.module('appDemo', ['MainControllers', 'MainServices'])
.constant('myConfig', {
'backend': 'http://localhost:1236'
})
.service('mailService', function() {
var mail = {
value: 'hello world'
};
var getMail = function() {
return mail;
}
var setMail = function(email) {
mail.value = email;
}
return {
getMail: getMail,
setMail: setMail
};
);
Setting the variable from controllerOne goes fine:
angular.module('MainControllers')
.controller('MemberController', function ($scope, mainService, appDemo) {
window.onbeforeunload = function (e) {
appDemo.setMail('test#test.com');
};
But when I get the setting variable from the controllerTwo than I get the default value:
angular.module('MainControllers')
.controller('EmailController', function($scope, appDemo) {
$scope.mailAddress = appDemo.getMail();
});
Each controller is in separate file.
what is wrong?
This may be because the service itself is being reloaded because as I can see you are setting the mail in the first controller on onbeforeunload.
Services can't persist on window reloads or page refresh. They get reloaded hence reinitialized every time you reload the page.
If you want to persist the values try putting it in localStorage or sessionStorage.
I have a server variable named currentPlayer that binds properly in the emit 'init' call, but won't bind in my broadcast.emit. The variable turnNumber which is passed through from the client first updates properly. When the pass event is fired I can see currentPlayer switching values in the terminal, but I'm stumped as to why it doesn't update in the view.
I had some trouble binding to primitive types before, so I tried going an extra step and assigning currentPlayer to an object array: $scope.globalVars = [{ currentPlayer: data.currentPlayer }], but that didn't help.
//server
var currentPlayer = 1;
socket.emit('init', {
currentPlayer: currentPlayer
});
socket.on('pass', function (data) {
currentPlayer = currentPlayer == 1 ? 2 : 1;
console.log(currentPlayer);
socket.broadcast.emit('pass', {
number: data.turnNumber,
currentPlayer: currentPlayer
});
});
//client
socket.on('init', function (data) {
$scope.globalVar.currentPlayer = data.currentPlayer;
});
socket.on('pass', function (data) {
$scope.globalVar.turnNumber = data.number;
$scope.globalVar.currentPlayer = data.currentPlayer;
});
//click event
$scope.globalVar.turnNumber++;
socket.emit('pass', {
turnNumber: $scope.globalVar.turnNumber
});
<!-- html -->
{{globalVar.currentPlayer}} {{globalVar.turnNumber}}
UPDATE:
I realized I could handle the current turn logic in my angular controller. I'm no longer changing the variable on the server and trying to pass it back to the client. Maybe as Chandermani says it's simply out of angular's context.
//server
socket.on('pass', function (data) {
socket.broadcast.emit('pass', {
number: data.turnNumber,
currentPlayer: data.currentPlayer
});
});
//client
socket.on('pass', function (data) {
$scope.globalVar.turnNumber = data.number;
$scope.globalVar.currentPlayer = data.currentPlayer;
});
//click event
$scope.globalVar.currentPlayer = $scope.globalVar.currentPlayer == 1 ? 2 : 1;
$scope.globalVar.turnNumber++;
socket.emit('pass', {
turnNumber: $scope.globalVar.turnNumber,
currentPlayer: $scope.globalVar.currentPlayer
});
These calls seem to be execution outside the anuglar context. Try to use $scope.$apply in the socket.on handlers, like
socket.on('pass', function (data) {
$scope.$apply(function() {
$scope.globalVar.turnNumber = data.number;
$scope.globalVar.currentPlayer = data.currentPlayer;
});
});