AngularJS does not update after value change - angularjs

My intention is to update the navigation bar after the user login. Basically, it should change Login to Hi, {{usr.username}} right after the login.
However, it does not update after logging in and I have to click on Login again to trigger the change. However, in the console, the user info is logged right after the login.
In the index.html, the part of the code looks like:
<div class="item" ng-click="loginmodal()" ng-hide="loggedIn">Log in</div>
<div class="item" ng-show="loggedIn">Hi, {{usr.username}}</div>
where $scope.loggedIn is initialized as false and $scope.usr as null. I am using firebase for authentication:
FirebaseRef.authWithPassword({
"email" : email,
"password" : password
}, function(error, authData) {
if (error) {
console.log('Login Failed!', error);
} else {
console.log('Authenticated successfully with payload:', authData);
FirebaseRef.child("users").child(authData.uid).once('value', function(dataSnapshot) {
$scope.usr = dataSnapshot.val();
});
$scope.loggedIn = true;
console.log($scope.usr);
console.log($scope.loggedIn);
}
});
In console, I have $scope.loggedIn as true, but have $scope.usras null.
Is it wrong how I am using the authWithPassword() function or can I force the change to be updated?

AngularJS won't update the view if any changes to the $scope object are done outside of its $digest loop.
But worry not, Firebase is such a popular tool it has a AngularJS service. It's called AngularFire and you should be using it instead of global Firebase object.
So your code will be something similar to:
var auth = $firebaseAuth(FirebaseRef);
auth.$authWithPassword({
email: email,
password: password
}).then(function (authData) {
console.log('Authenticated successfully with payload:', authData);
var sync = $firebase(FirebaseRef.child("users").child(authData.uid));
var syncObject = sync.$asObject();
syncObject.$bindTo($scope, "usr");
}).catch(function (error) {
console.error('Login Failed!', error);
});
Read more in the documentation of AngularFire

Try calling $scope.$digest() right after changing $scope.usr value.
Anyway, notice that you call to Firebase to get the user is asynchronous, so I wouldn't put dependent code after this call, but inside the callback.

Call $scope.$apply();
FirebaseRef.child("users").child(authData.uid).once('value', function(dataSnapshot) {
$scope.$apply(function(){
$scope.usr = dataSnapshot.val();
});
});

Related

Using $scope in AngularJS to change value at index.html in routing

I'm making a single page app in AngularJS using Firebase and using the side nav bar on index.html.
And after login, I want the username should be on the side nav bar but the $scope is working for the current page on the controller is working.
scotchApp.controller('mainController', function($scope) {
$scope.validateLogin = function()
{
var email = $scope.login.userName + "#xyz.co";
var password = $scope.login.password;
firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
$scope.message = "please enter the correct details";
});
firebase.auth().onAuthStateChanged(function(user)
{
if(user)
{
$scope.usermobile = $scope.login.userName;
window.location.assign("/#/equipment");
}
});
}
$scope.message = '';
});
The current user is available in firebase.auth().currentUser as described in the docs so in your mainController you don't need to listen for auth changes.
In your code you are attaching a new listener each time the user tries to login, but what you actually want is to respond to one successful login, so just add a then to your sign in call:
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function (user) {
console.log('the logged in user: ', user);
// Go to the other route here.
// It is recommended to use the router instead of "manually" changing `window.location`
})
.catch(function(error) {
$scope.message = "please enter the correct details";
});

Make facebook posts with ionic/angular app

I'm creating an app with the ionic framework and integrate the facebookConnectPlugin for login and making posts to a fan page.
The login part is working properly, I can see the user data and display on the app. The problem I'm having is when I try to make a post to facebook.
This is the complete controller that manage the login and the post
.controller('signupCtrl', function($scope, $state, $q, UserService, $ionicLoading){
// This is the success callback from the login method
var accesstoken;
var fbLoginSuccess = function(response){
if (!response.authResponse){
fbLoginError("Cannot find the authResponse");
return;
}
var authResponse = response.authResponse;
accesstoken = authResponse.accessToken;
getFacebookProfileInfo(authResponse).then(function(profileInfo){
// For the purpose of this example I will store user data on local storage
UserService.setUser({
authResponse: authResponse,
userID: profileInfo.id,
name: profileInfo.name,
email: profileInfo.email,
picture: "http://graph.facebook.com/" + authResponse.userID + "/picture?type=large"
});
$ionicLoading.hide();
}, function(fail){
// Fail get profile info
alert('profile info fail ' + fail);
});
};
// This is the fail callback from the login method
var fbLoginError = function(error){
alert('fbLoginError ' + error);
$ionicLoading.hide();
};
// This method is to get the user profile info from the facebook api
var getFacebookProfileInfo = function (authResponse){
var info = $q.defer();
facebookConnectPlugin.api('/me?fields=email,name&access_token=' + authResponse.accessToken, null,
function (response) {
console.log(response);
info.resolve(response);
},
function (response) {
console.log(response);
info.reject(response);
}
);
return info.promise;
};
//This method is executed when the user press the "Login with facebook" button
$scope.facebookSignIn = function(){
console.log('---> facebookSignIn');
facebookConnectPlugin.getLoginStatus(function(success){
if (success.status === 'connected'){
// The user is logged in and has authenticated your app, and response.authResponse supplies
// the user's ID, a valid access token, a signed request, and the time the access token
// and signed request each expire
//alert('getLoginStatus ' + success.status);
// Check if we have our user saved
var user = UserService.getUser('facebook');
if (!user.userID){
alert('UNO');
getFacebookProfileInfo(success.authResponse).then(function(profileInfo) {
// For the purpose of this example I will store user data on local storage
UserService.setUser({
authResponse: success.authResponse,
userID: profileInfo.id,
name: profileInfo.name,
email: profileInfo.email,
picture: "http://graph.facebook.com/" + success.authResponse.userID + "/picture?type=large"
});
//$state.go('menu.home');
}, function(fail){
// Fail get profile info
alert('profile info fail ' + fail);
});
}else{
//alert('DOS');
$state.go('menu.home');
var fan_token = 'EAAH1eElPgZBl1jwZCI0BADZBlrZCbsZBWF5ig29V1Sn5ABsxH1o4kboMhpjZBDfKtD1lfDK1dJLcZBI4gRBOF2XGjOmWMXD0I8jtPZA4xLJNZADarOGx8fiXBRZCTOaxwBLQEwRjsvaqTtb2DTCI0Qdo3haX6vqHlJoWMZD';
console.log('access token', accesstoken);
facebookConnectPlugin.api(
'/186259017448757/feed',
'POST',
{
access_token: fan_token,
'message':'HOLA!'
},
function(response){console.log(response);alert(response.id)}
)
}
}else{
// If (success.status === 'not_authorized') the user is logged in to Facebook,
// but has not authenticated your app
// Else the person is not logged into Facebook,
// so we're not sure if they are logged into this app or not.
alert('getLoginStatus ' + success.status);
$ionicLoading.show({
template: 'Logging in...'
});
// Ask the permissions you need. You can learn more about
// FB permissions here: https://developers.facebook.com/docs/facebook-login/permissions/v2.4
facebookConnectPlugin.login(['email', 'public_profile'], fbLoginSuccess, fbLoginError);
}
});
};
})
This is the part where I try to make a post to a facebook wall
facebookConnectPlugin.api('/181297057448657/feed', 'POST', {access_token: fan_token, 'message':'HOLA!'},
function(response){
console.log(response);
alert(response.id)
}
)
I went to https://developers.facebook.com/tools/explorer to generate the access tokens, tried with several tokens (user, fanpage, etc) but any seem to work. I've also used this code snippet provided in the facebook devs explorer tool
FB.api(
'/174801556748297/feed',
'POST',
{"message":"testing3"},
function(response) {
// Insert your code here
}
);
The result is always the same, I get a JSON error in the response object and no facebook post to the wall
Any help would be really appreciated!
PD: app ID's have been modified, that why they don't match. Same with the tokens and fan page ID
I used following in my app to post ,Reference https://github.com/ccoenraets/sociogram-angular-ionic
$scope.share = function () {
OpenFB.post('/me/feed', $scope.item)
.success(function () {
console.log("done");
$ionicLoading.hide();
$scope.item.message="";
$ionicLoading.show({ template: 'Post successfully on Facebook!', noBackdrop: true, duration: 2000 });
$scope.status = "This item has been shared from OpenFB";
})
.error(function(data) {
$ionicLoading.hide();
alert(data.error.message);
});
};
HTML
<div class="media-body">
<textarea placeholder="What's on your mind?" ng-model="item.message"></textarea>
</div>
<hr style="margin-top: -1px;" />
<div style="text-align:right;padding-right:20px;padding-bottom:10px;">
<button class="fb-login" ng-click="share()">Post to Facebook</button>
</div>

On Auth State changed AngularFire

Trying to authenticate an user using firebase. Started my app using firebase 2.xx but even after upgrading to Firebase 3.xx, throwing
error "onAuthStateChanged is not a function".
This is how my login function looks like-
.controller('HomeCtrl', ['$scope','$location','CommonProp','$firebaseAuth', '$firebaseObject',function($scope,$location,CommonProp,$firebaseAuth,$firebaseObject) {
var firebaseObj = $firebaseObject(rootRef);
var loginObj = $firebaseAuth(firebaseObj);
$scope.SignIn = function($scope, user) {
event.preventDefault(); // To prevent form refresh
var username = user.email;
var password = user.password;
loginObj.$signInWithEmailAndPassword({
email: username,
password: password
})
.then(function(user) {
// Success callback
console.log('Authentication successful');
$location.path("/welcome");
CommonProp.setUser(user.password.email);
}, function(error) {
// Failure callback
console.log(error);
});
}
}]);
Your problem is that you are passing a $firebaseObject to $firebaseAuth().
So make sure you are initializing your [$firebaseAuth][1] object like the following and then your code should work properly.
var loginObj = $firebaseAuth();
Working jsFiddle for demonstrating.
You can check here the documentation for AngularFire2

Angular API call fails in MEAN application

In a MEAN app I am trying to allow an authorised user (email and password login) to change their username.
I can successfully use Postman to PUT a new username to http://localhost:3000/api/users/xxxxxxxxxxxxxxxx.
But the angular code fails.
Here is the relevant part of the edit page:
<form ng-submit="user.saveUser()">
<div class="form-group">
<label> New Username</label>
<input type="text" class="form-control" ng-model="user.userData.name">
</div>
Here is the controller:
.controller('userEditController', function($routeParams, User) {
var vm = this;
vm.type = 'edit';
User.get($routeParams.user_id)
.success(function(data) {
vm.userData = data;
});
// function to save the user
vm.saveUser = function() {
vm.processing = true;
vm.message = '';
// call the userService function to update
User.update($routeParams.user_id, vm.userData)
.success(function(data) {
vm.processing = false;
// clear the form
vm.userData = {};
// bind the message from our API to vm.message
vm.message = data.message;
});
};
});
Here is the service:
// update a user
userFactory.update = function(id, userData) {
return $http.put('/api/users/' + id, userData);
};
at this point userData contains name: “Fred” or whatever was input to the form
and here is the api.js
apiRouter.route('/users/:user_id')
// get the user with that id
.get(function(req, res) {
User.findByIdAndUpdate(req.params.user_id, function(err, user) {
if (err) return res.send(err);
// return that user
res.json(user);
});
})
// update the user with this id
.put(function(req, res) {
console.error(req.params.user_id);
User.findById(req.params.user_id, function(err, user) {
if (err) return res.send(err);
// set the new user information if it exists in the request
if (req.body.name) user.name = req.body.name;
// save the user
user.save(function(err) {
if (err) return res.send(err);
// return a message
res.json({ message: 'User updated!' });
});
});
});
(I had to use findByIdAndUpdate instead of findById because of a CastError.)
Although the console states:
XHR finished loading: PUT http:/localhost/3000/api/users/user_id
The value of req.params.user_id is just user_id.
The terminal shows:
PUT /api/users/user_id 200 4.040 ms - 2273
GET /api/users/user_id - - ms - -
GET /api/users/user_id - - ms - -
GET /api/users/user_id - - ms - -
Like I say Postman can communicate with the API and can update without problems. I am stumped, and hopefully someone will put me out of my misery
I had to change tack with this one. The fact that a manually entered user_id in Postman worked should have told me that the user_id provided by the Angular code was not correct. So I made sure that the JWT included the user_id:
var token = jwt.sign({
name: user.name,
email: user.email,
user_id: user._id
Then added an api endpoint to get user information:
apiRouter.get('/me', function(req, res) {
res.send(req.decoded);
});
Then connected a service:
userFactory.get = function() {
return $http.get('/api/me/');
};
Then in the controller I could call get:
User.get()
.success(function(result) {
$scope.user_id = result.user_id;
});
$scope.user_id now has the correct user_id which I can pass into the update method:
User.update($scope.user_id, vm.userData)
.success(function(data)
So now it works as intended.

Firebase Angular OAuth with Google email scope, auth.$authWithOAuthPopup vs ref.authWithOAuthPopup

I'm successfully using Firebase's angular library to auth users against Facebook and Google, but I'm having troubling retrieving the user's email when using firebaseAuth's $authWithOAuthPopup.
Here's my login function.
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseAuth(ref);
loginGoogle: function () {
console.log('Logging in Google.');
return auth.$authWithOAuthPopup('google', function(error, user){
//TODO: Handle Failed login better
console.log('Google login failed');
console.log(error);
},{
scope: 'email'
});
};
This will pop up the google auth window and log in successfully. But, in the access permissions window, it doesn't request the 'email' scope access.
If I use ref.authWinOAuthPopup(...) instead of auth.$authWithOAithPopup(...) it does properly request the email perms, and delivers that info after auth.
Am I doing something wrong here? Or, is it an Angularfire bug that I should be reporting?
Angularfire v0.9.2.
After digging in further I found that the $firebaseAuth.$authWithOAuthPopup takes only two arguments (provider and options), whereas the Firebase.authWithOAuthPopup takes three (provider, onComplete callback, options). So, using refactoring to use the returned promise instead of passing in a callback function fixed the issue.
To be more clear, I'd like to add my snippets to show how to pass the e-mail scope to google oAuth.
As you mentioned, if you're using the promise to do the authentication instead of the callback you can pass the option for the email scope to the auth. call as second parameter and then the e-mail address will be available in the payload.
Please have a look at the following snippet:
$scope.loginGoogle = function() {
Auth.$authWithOAuthPopup("google", {scope: ['email']}).then(function(authData) {
// handle authData in onAuth handler in app.js in run method with Auth.$onAuth(function(authData) { ... });
console.log("Authenticated successfully with payload:", authData);
$location.path(REDIRECT_ROUTE);
})
.catch(function(err) {
$scope.err = errMessage(err);
});
};
function errMessage(err) {
var msg = "";
//return angular.isObject(err) && err.code? err.code : err + '';
switch (err.code) {
case "INVALID_EMAIL":
case "INVALID_PASSWORD":
case "INVALID_USER":
console.log("The specified user account email is invalid.");
msg = "E-mail or password is invalid.";
break;
/*
case "INVALID_PASSWORD":
console.log("The specified user account password is incorrect.");
break;
case "INVALID_USER":
console.log("The specified user account does not exist.");
break;
default:
// password or email empty;
console.log("Error logging user in:", err);*/
};
return msg;
}
angular.module('firebase.auth', ['firebase', 'firebase.utils'])
.factory('Auth', ['$firebaseAuth', 'fbutil', function($firebaseAuth, fbutil) {
return $firebaseAuth(fbutil.ref());
}]);
This is what I did and it worked for me
.config(function ($firebaseRefProvider) {
$firebaseRefProvider.registerUrl('https://****.firebaseio.com/');
})
Then in controller
loginWithGoogle: function(){
var ref = $firebaseRef.default;
ref.authWithOAuthPopup("google", function(error, authData) {
if (error) {
...
} else {
console.log(authData.google.email);
}
},{scope: 'email'});
}

Resources