AngularJS - How to authenticate in first submission? - angularjs

I have a login function in Angularjs, it works only when I submit it the second time. How to resolve it?
This is the code:
.controller('LoginCtrl',
['$scope', '$rootScope', '$location', 'AuthenticationService',
function ($scope, $rootScope, $location, AuthenticationService) {
// reset login status
AuthenticationService.ClearCredentials();
$scope.login = function () {
$scope.dataLoading = true;
console.log('Entra '+$scope.username);
AuthenticationService.Login($scope.username, $scope.password, function(response) {
if(response.success) {
AuthenticationService.SetCredentials($scope.username, $scope.password, $rootScope.datos.grupo);
$location.path('/');
console.log('Comprueba y redirecciona');
} else {
console.log('Falla');
$scope.error = response.message;
$scope.dataLoading = false;
}
});
};
}]);

I need to make a $scope.$apply() right after changed the location and call replace() to let Angular know that things have changed.
Thank you.

Related

angularjs using $on and $broadcast to communicate between a master controller to another controller

I am trying to set communication between two angular controllers (service is not an option). and I am failing desperately.
here is some of my code...
i tried using both $emit and $broadcast
invoiceApp.controller('masterReportConrtoller', ['$scope', '$location', 'authService', 'usSpinnerService', 'dateService', 'settingsService','$rootScope',
function ($scope, $location, authService, usSpinnerService, dateService, settingsService, $rootScope )
////Is User Valid
////
//$rootScope.$on("masterReportConrtoller", function () {
// $scope.parentmethod();
// });
//$scope.parentmethod = function () {
// //
$scope.masterReportConrtoller.getUserDetails = function () {
debugger;
settingsService.getUserDetails().then(function (response) {
var loginData = {
userName: response.d.user.Email,
password: response.d.user.UserPassword
};
authService.login(loginData).then(function (response) {
debugger;
$scope.Limit = response.d.organization.Limit;
});
$scope.Limit = response.d.organization.Limit;
$scope.DocumentUsage = response.d.organization.DocumentUsage;
$scope.ExpirationDate = $scope.DateConvertfromJson(response.d.organization.ExpirationDate);
var fullDate = new Date();
if (fullDate <= $scope.ExpirationDate) {
$scope.ISvalidUser = false;
$rootScope.$broadcast('masterReportConrtoller', false);
}
else {
$rootScope.$broadcast('masterReportConrtoller', true);
}
});
}
}]);
invoiceApp.controller('InvoiceController', ['$scope', '$location', '$cookieStore', 'documentService', 'dialogs', 'usSpinnerService', 'settingsService', 'associatedEmailsService', '$rootScope',
function ($scope, $location, $cookieStore, documentService, dialogs, usSpinnerService, settingsService, associatedEmailsService, $rootScope) {
$rootScope.$on('masterReportConrtoller');}
Based on your parent - child controller relationship, you can use $scope.$broadcast and $scope.$on in your code.
Try something like this:
//masterReportConrtoller
$scope.$broadcast("myCustomEvent", { isValidUser: false });
//InvoiceController
$scope.$on("myCustomEvent" , function(event, data){
//do something with data
});
Please note that this will work if masterReportConrtoller is the parent controller and InvoiceController is the child controller. If this is not the case, then use $rootScope.$broadcast and $rootScope.$on.
You can find more details here.
You can use $localStorage , $stateParams or $cookies or even ... I generally prefer $stateParams to send values and object to states and controller.
$state.go('state2', { someParam : 'broken magic' });
read file using $stateParams from controller . Details can be found here

factory is unable to convey data to another controller

I am building a spa with angular and slim framework. As per the bellow mentioned code, what i am trying to do is, login page controller will pass data to landing page controller upon successful submission of user/psw. When i place the factory outside the http call/ log in function it gets the data but on the landing page factory does not deliver the data. And when i place it inside it stops to work. Please help me....
this factory is for sharing data across controllers
appDls.factory('sharedFactory', function () {
var dataTobeShared = {};
var interface = {};
interface.add = function (d) {
dataTobeShared = d;
}
interface.put = function () {
return dataTobeShared;
}
return interface;
});
this controller is for the main portal user redirection and portal rendering
appDls.controller('DlsappController', ['$scope', '$state', 'multipartForm', 'sharedFactory', '$window', function ($scope, $state, multipartForm, sharedFactory, $window) {
$scope.Userdata = [];
$scope.login = function () {
var url = "../scripts/routes.php/authen";
multipartForm.post(url, $scope.login).then(function (d) {
$scope.Userdata.push(d.data[0]);
sharedFactory.add($scope.Userdata);
$window.location.href = '../portal/landing.php';
});
}
}]);
this controller is for landing page routing
appDls.controller('landingController', ['$scope', '$state', 'multipartForm', 'sharedFactory', function ($scope, $state, multipartForm, sharedFactory) {
$scope.UserInfo = sharedFactory.put();
$scope.$watch('UserInfo', function (newValue, oldValue) {
/*here we can use the user data from login page*/
if (newValue.length == 1) {
alert(newValue[0].fullname);
$state.go(newValue[0].proftype);
} else {
alert("user not logged in successfully!");
$state.go('default');
}
}, true);
}]);
When you do sharedFactory.add($scope.Userdata); your $scope.Userdata is another object, which is not watched by landingController. By reassigning dataToBeShared in sharedFactory.add function, you lose the reference to original object, so it is not reachable anymore from code.
To make landingController see the changes you need either to reimplement sharedFactory.add function to push values in sharedFactory.dataTobeShared array or use some event-based notification, not $watch.
Here is the jsfiddle to illustrate my words.
appDls.factory('sharedFactory', function () {
var dataTobeShared = {};
return
{
add: function (d) {
dataTobeShared = d;
}
put: function () {
return dataTobeShared;
}
}
});
appDls.controller('DlsappController', ['$scope', '$state', 'multipartForm', 'sharedFactory', '$window', function ($scope, $state, multipartForm, sharedFactory, $window) {
$scope.Userdata = [];
$scope.$watch('login',function () {
var url = "../scripts/routes.php/authen";
multipartForm.post(url, $scope.login).then(function (d) {
$scope.Userdata.push(d.data[0]);
sharedFactory.add($scope.Userdata);
$window.location.href = '../portal/landing.php';
});
}
}]);
appDls.controller('landingController', ['$scope', '$state', 'multipartForm', 'sharedFactory', function ($scope, $state, multipartForm, sharedFactory) {
$scope.UserInfo = sharedFactory.put();
$scope.$watch('UserInfo', function (newValue, oldValue) {
/*here we can use the user data from login page*/
if (newValue.length == 1) {
alert(newValue[0].fullname);
$state.go(newValue[0].proftype);
} else {
alert("user not logged in successfully!");
$state.go('default');
}
}, true);
}]);
The watcher needs to fetch the value from the factory on each digest cycle, and update the $scope variable.
appDls.controller('landingController', ['$scope', '$state', 'multipartForm', 'sharedFactory', function ($scope, $state, multipartForm, sharedFactory) {
//$scope.UserInfo = sharedFactory.put();
//$scope.$watch('UserInfo', function (newValue, oldValue) {
$scope.$watch(sharedFactory.put, function (newValue, oldValue) {
//UPDATE scope variable
$scope.UserInfo = newValue;
/*here we can use the user data from login page*/
if (newValue.length == 1) {
alert(newValue[0].fullname);
$state.go(newValue[0].proftype);
} else {
alert("user not logged in successfully!");
$state.go('default');
}
}, true);
}]);
The original code only set the scope variable once upon initialization of the controller. It needs to fetch the value from the factory on each digest cycle.

Angularjs cannot get data from service

I'm trying to pass data from one controller to another using a service, however no matter what I'm trying it always returns 'undefined' on the second controller. Here is my service :
app.service('myService', ['$rootScope', '$http', function ($rootScope, $http) {
var savedData = {}
this.setData = function (data) {
savedData = data;
console.log('Data saved !', savedData);
}
this.getData = function get() {
console.log('Data used !', savedData);
return this.savedData;
}
}]);
Here is controller1 :
.controller('HomeCtrl', ['$scope','$location','$firebaseSimpleLogin','myService','$cookies','$window', function($scope,$location, $firebaseSimpleLogin, myService, $cookies, $window) {
loginObj.$login('password', {
email: username,
password: password
})
.then(function(user) {
// Success callback
console.log('Authentication successful');
myService.setData(user);
console.log('myservice:', myService.getData()); // works fine
}]);
And then controller2:
// Dashboard controller
.controller('DashboardCtrl', ['$scope','$firebaseSimpleLogin','myService',function($scope,$firebaseSimpleLogin, $location, myService) {
console.log('myservice:', myService.getData()); //returns undefined
}]);
That is simple code, unfortunately I've been struggling for a few hours now, any suggestion ? Thanks.
Created a fiddle here:
http://jsfiddle.net/frishi/8yn3nhfw/16
To isolate the problem, can you remove the dependencies from the definition for myService and see if that makes it work? Look at the console after you load the fiddle.
var app = angular.module('app', [])
.service('myService', function(){
this.getData = function(){
return "got Data";
}
})
I assume the issue is that you are returning this.savedData in the service. Try returning savedData.
this behaves different in Javascript than in other languages.

Get AnonymousID in Razor

I want get HttpContext.Current.Request.AnonymousID of users in Razor and then send it to an action in a controller in this way:
<script>
app.controller('loginController', function ($http, $scope, $location, $rootScope) {
$scope.login = function () {
//Send Anonymous to UserLogin action
$http.post("/Accounts/UserLogin?anonymous="+AnonymousId, $scope.model).success(function (response) {
$scope.message = response;
window.location = '/';
$rootScope.ShowSpinner = false;
});
}
});
</script>
Is there any way to do this?
In razor you can have something like
#{
// Just to make my expression smaller
var anonymousId = HttpContext.Current.Request.AnonymousID;
}
<script>
angular.module("someModule").value("anonymousId", "#anonymousId" );
</script>
Note injecting Razor is just normal. If it fails, try wrapping in (), like "#(anonymousId)". The only trick is that I just wrapped the value in quotes so that it's a string in JavaScript.
Then you can inject this value into your Angular controller:
<script>
app.controller('loginController',
function ($http, $scope, $location, $rootScope, anonymousId) {
$scope.login = function () {
//Send Anonymous to UserLogin action
$http.post("/Accounts/UserLogin?anonymous="+anonymousId, $scope.model)
.success(function (response) {
...
});
}
});
</script>
Of course you can also write it directly in the controller as well...
....
$http.post("/Accounts/UserLogin?anonymous="
+ "#(HttpContext.Current.Request.AnonymousID)", $scope.model).
....

Initiate a service and inject it to all controllers

I'm using Facebook connect to login my clients.
I want to know if the user is logged in or not.
For that i use a service that checks the user's status.
My Service:
angular.module('angularFacebbokApp')
.service('myService', function myService($q, Facebook) {
return {
getFacebookStatus: function() {
var deferral = $q.defer();
deferral.resolve(Facebook.getLoginStatus(function(response) {
console.log(response);
status: response.status;
}));
return deferral.promise;
}
}
});
I use a promise to get the results and then i use the $q.when() to do additional stuff.
angular.module('angularFacebbokApp')
.controller('MainCtrl', function ($scope, $q, myService) {
console.log(myService);
$q.when(myService.getFacebookStatus())
.then(function(results) {
$scope.test = results.status;
});
});
My problem is that i need to use the $q.when in every controller.
Is there a way to get around it? So i can just inject the status to the controller?
I understand i can use the resolve if i use routes, but i don't find it the best solution.
There is no need to use $q.defer() and $q.when() at all, since the Facebook.getLoginStatus() already return a promise.
Your service could be simpified like this:
.service('myService', function myService(Facebook) {
return {
getFacebookStatus: function() {
return Facebook.getLoginStatus();
}
}
});
And in your controller:
.controller('MainCtrl', function ($scope, myService) {
myService.getFacebookStatus().then(function(results) {
$scope.test = results.status;
});
});
Hope this helps.
As services in angularjs are singleton you can create new var status to cache facebook response. After that before you make new call to Facebook from your controller you can check if user is logged in or not checking myService.status
SERVICE
angular.module('angularFacebbokApp')
.service('myService', function myService($q, Facebook) {
var _status = {};
function _getFacebookStatus() {
var deferral = $q.defer();
deferral.resolve(Facebook.getLoginStatus(function(response) {
console.log(response);
_status = response.status;
}));
return deferral.promise;
}
return {
status: _status,
getFacebookStatus: _getFacebookStatus
}
});
CONTROLLER
angular.module('angularFacebbokApp')
.controller('MainCtrl', function ($scope, $q, myService) {
console.log(myService);
//not sure how do exactly check if user is logged
if (!myService.status.islogged )
{
$q.when(myService.getFacebookStatus())
.then(function(results) {
$scope.test = results.status;
});
}
//user is logged in
else
{
$scope.test = myService.status;
}
});

Resources