I am new in AngularJs and can not figure out with such problem.
I try to change the variable in the scope that unassuming way.
.controller('AuthController', function($scope,Auth) {
$scope.submit = function() {
Auth.login($scope.username,$scope.password, function(result){
$scope.result = result
});
}
})
Where Auth is a service which makes GET request to server and gets response like this:
{ 'status': 1, 'message': "User does not found!"}
But my variable does not refresh in my template. When I put this
$scope.result = { 'status': 1, 'message': "User does not found!"}
outside the function $scope.submit. It works fine.
This is my routing.
$stateProvider
.state('index', {
url: "/",
templateUrl: "/static/templates/_index.html",
})
My template is.
<div class="alert" >{{ result.message }}</div>
Can someone explaine me what do I do wrong?
Thanks.
This is my service.
function login(username, password, callback) {
return $http.post('/api/login/', {
username: username, password: password
}).success(callback);
}
After inserting
Auth.login($scope.username,$scope.password, function(result){
$scope.result = result
console.log($scope.result);
I see correct data in my firebug.
Object { status=1, message="User does not found!"}
$scope.$apply(); - gives me Error: [$rootScope:inprog] http://errors.angularjs.org/1.4.0/$rootScope/inprog?p0=%24digest
Are you sure Auth.login() doesn't return a promise. It looks like it wants to, in which case try...
Auth.login($scope.username, $scope.password)
.then(function(result){
$scope.result = result
});
Hard to say without seeing your Auth service.
If your Auth.login() returns a promise you can use its then function to define success and error handler e.g:
Auth.login($scope.username, $scope.password)
.then(function(result){// success handler
$scope.result = result
$scope.$apply();
},function(error){// error handler
console.log(error);
});
However if it makes an ajax call and does not return a promise, you can use $q service to return a promise by yourself. Here's how you can do it:
var deferred = $.defer();
deferred.resolve($.ajax({
// Your ajax call
}));
You can return promise using return deferred.promise.
Note : Make sure you inject $q service in your Auth service.
The problem was decided by changing
$scope.result = result.data;
on
$scope.blabla = result.data;
And after that magic my template finally show me {{ blabla }} variable.
Angular dose not live up my expectation :-(
Related
I am using Ionic Framework and Firebase is my BaaS.
Controller:
.controller('ProfileCtrl', function($scope, AuthService, DatabaseService) {
console.info('** ProfileCtrl **');
var user = firebase.auth().currentUser;
$scope.public = {};
DatabaseService.getUserPublicInfo(user.uid)
.then(function(infoSnap) {
infoSnap.forEach(function(item) {
$scope.public[item.key] = item.val();
});
});
})
Service:
.service('DatabaseService', function($q) {
this.getUserPublicInfo = function(uid) {
return firebase.database().ref('/users/'+uid+'/public/').once('value');
}
}
In my HTML view I have the following:
<div><h3>{{public.firstname}} {{public.lastname}}</h3></div>
No error and when debugging, $scope.public.firstname as the correct value in it but nothing is displayed.
I have a button in my HTML view ; when I click on it, it changes page but just before page switches, I see the firstname appearing. When I go back to my view, the firstname is well displayed.
I tried to wrap getUserPublicInfo in $scope.$apply() in my controller but I get the "$digest already in progress" error...
Please, help, it's driving me crazy !
Thanks in advance
To resove, "$digest already in progress" error... put $scope .$appy inside timeout service.
DatabaseService.getUserPublicInfo(user.uid)
.then(function(infoSnap) {
infoSnap.forEach(function(item) {
$scope.public[item.key] = item.val();
$timeout(function(){
$scope.$apply()
},1)
});
});
Edit 1: Try this to avoid using $scope.$apply(). I haven't tested it. But it should work.
DatabaseService.getUserPublicInfo(user.uid)
.then(function(infoSnap) {
$scope.updatePublic(infoSnap)
});
});
$scope.updatePublic = function (infoSnap) {
infoSnap.forEach(function(item) {
$scope.public[item.key] = item.val();
})
}
I used $q to create a promise. By doing the initial Firebase promise is resolved within the Angular scope:
this.getUserPublicInfo = function(uid) {
console.info('getUserPublicInfo - get user public information for uid: '+uid);
var deferred = $q.defer();
firebase.database().ref('/users/'+uid+'/public/').once('value')
.then(function(snap) {
deferred.resolve(snap);
})
.catch(function(error) {
deferred.reject(error);
});
return deferred.promise;
}
I have the simplest angular controller:
tc.controller('PurchaseCtrl', function () {
var purchase = this;
purchase.heading = 'Premium Features';
this.onSuccess = function (response) {
console.log('Success', response);
lib.alert('success', 'Success: ', 'Loaded list of available products...');
purchase.productList = response;
};
this.onFail = function (response) {
console.log('Failure', response);
};
console.log('google.payments.inapp.getSkuDetails');
lib.alert('info', 'Working: ', 'Retreiving list of available products...');
google.payments.inapp.getSkuDetails(
{
'parameters': {'env': 'prod'},
'success': purchase.onSuccess,
'failure': purchase.onFail
});
});
And the view:
<div class="col-md-6 main" ng-controller="PurchaseCtrl as purchase">
{{purchase}}
</div>
This prints out:
{"heading":"Premium Features"}
I thought that when the callback returned, the view would be update with any new data. Am I missing something? The callback returns and I see the dtaa in the console.
Using the $scope pattern I think that I would use $scope.$apply to async method, but I'm not sure how to do that here.
Using controllerAs does not change the way digest cycle works or anything. It is just a sugar that adds a property (with the name same as alias name when used) to the current scope with its value pointing to the controller instance reference. So you would need to manually invoke the digest cycle (using scope.$apply[Asyc]() or even with a dummy $timeout(angular.noop,0) or $q.when() etc) in this case as well. But you can avoid injecting scope by abstracting it out into an angular service and returning a promise from there, i.e
myService.$inject = ['$q'];
function myService($q){
//pass data and use it where needed
this.getSkuDetails = function(data){
//create deferred object
var defer = $q.defer();
//You can even place this the global variable `google` in a
//constant or something an inject it for more clean code and testability.
google.payments.inapp.getSkuDetails({
'parameters': {'env': 'prod'},
'success': function success(response){
defer.resolve(response);// resolve with value
},
'failure': function error(response){
defer.reject(response); //reject with value
}
});
//return promise
return defer.promise;
}
}
//Register service as service
Now inject myService in your controller and consume it as:
myService.getSkuDetails(data).then(function(response){
purchase.productList = response;
}).catch(function(error){
//handle Error
});
Hey guys so i am using firebase and angular to build a sample application.
This is the registration function
$scope.register = function (){
Authentication.register($scope.user)
.then(function(user){
Authentication.login($scope.user);
})
.then(function(user){
$timeout(function(){
$location.path('/meetings');
}, 5);
})
.catch(function(error){
$scope.message = error.toString();
});
} //register
this function calls to methods in this factory
myApp.factory('Authentication', function($firebase,
$firebaseAuth,$location, FIREBASE_URL){
var ref = new Firebase (FIREBASE_URL);
var auth = $firebaseAuth(ref);
var myObject = {
login : function (user){
return auth.$authWithPassword({
email: user.email,
password: user.password
});
}, // login
logout: function (){
return auth.$unauth();
},
register : function (user){
return auth.$createUser(user.email,user.password);
} //register
} //myObject
return myObject;
});
here is the status.js controller which changes my index based on whether the user is logged in or not
auth.$onAuth(function(authData){
if (authData){
console.log("i entered authData");
$scope.userStatus = authData.password.email;
} else {
$scope.userStatus = false;
}
});
part of index.html file
<div class="userinfo"
ng-controller="StatusController" ng-show="userStatus">
<span class="user">Hi {{userStatus}}</span>
Log Out
</div>
my problem is that the ng-view needs a page refresh to show the new value. its not showing it automatically but my code works. if i refresh the page manually i can see that the user got registered and logged in.
Search for about 2 hours now and $scope.$apply here does nt seem to be the case.
Thank you in advance
I wanna thank you guys for the possible solutions but it seems that the solution lies in the $timeout variable.
Because the registration function below talks with an API and i am working from a local environment using GulpJS there is a delay in talking between my script and the Firebase API.
$scope.register = function (){
Authentication.register($scope.user)
.then(function(user){
Authentication.login($scope.user);
})
.then(function(user){
$timeout(function(){
$location.path('/meetings');
}, 5);
})
.catch(function(error){
$scope.message = error.toString();
});
} //register
Thats why i put a $timeout angular function in there in the first place but i forgot that the number 5 in input in the $timeout function is in milliseconds and it seems because of my setup(using a local environment while talking to the Firebase API online) i found that if i use a 2 second delay in the redirection now ng-show changes automatically without manually refreshing the page.
correct code would be the one below:
$scope.register = function (){
Authentication.register($scope.user)
.then(function(user){
Authentication.login($scope.user);
})
.then(function(user){
$timeout(function(){
$location.path('/meetings');
}, 2000);
})
.catch(function(error){
$scope.message = error.toString();
});
} //register
I suspect that if i use my angular app on the web i could possibly lower the delay or even remove the $timeout function completely.
After i have updated a user in angularjs I will update the $scope.user with the new userdata. One way is to do an new api request to get all users. But i think, its better to update the $scope. I found $apply, but i'am not sure how to use it.
app.controller('UserCtrl', function( $scope, APIService ) {
$scope.users = APIService.query({ route:'users' });
$scope.activate = function( user ) {
var updateUser = {};
if(user.activated) {
updateUser.activated = false;
} else {
updateUser.activated = true;
}
APIService.update({ route:'users', id: user._id }, updateUser, function(updatedUser) {
//update $scope.users with new data from updatedUser;
});
}
});
The updatedUser looks like this:
{"__v":0,"_id":"535aa89d8b2766d012e14c21","activated":true,"role":"user","local":{"surname":"Carter","prename":"Rob","password":"459DS","email":"test"},"$promise":{},"$resolved":true}
the service:
app.service("APIService", function( $resource ) {
return $resource('http://localhost:3000/api/:route/:id', { route: "#route", id: "#id" }, {
'update': { method: 'PUT' }
});
});
If you're using ngRoute use:
$route.reload()
Causes $route service to reload the current route even if $location hasn't changed.
As a result of that, ngView creates new scope, reinstantiates the controller.
and if you're using ui-router:
$state.reload();
However I think a better way would be to recall the $resource call again:
var getUsers=function(){
$scope.users = APIService.query({ route:'users' });
}
You can call it initially like this:
getUsers();
and in the callback of your update:
APIService.update({ route:'users', id: user._id }, updateUser, function(updatedUser) {
getUsers();
});
EDIT
I'm not sure what you mean by "updating the scope"? You mean rerunning the controller again? In that case you're making a fresh API call again, the same thing as just calling the getUsers() method I suggested. If you mean you want to update an array that sits on your $scope with the new data of the user, rather than calling the server to get the entire users again, then in the callback of your update method do something like this:
angular.forEach($scope.users,function(user,key){
if(user._id == updatedUser._id){
$scope.users[key]=updatedUser;
}
})
I have one service method items.getItems();
getItems: function(callback){
$http({
url: url,
method: "POST"
}).success(function(data, status){
callback(data);
}
}).error(function(err){
console.error('Error: %s error: %O', 'getLanguages[*] failed.', err);
});
}
I use it in my controller, I would like to call it inside the function:
$scope.param= function(){
items.getItems(function(data){
$scope.selectedItemsUpdate = data;
});
return $scope.selectedItemsUpdate}
and in my html page to do like something :
<div data-dy-item data-items="param()"
</div>
But it doens't work
The call is asynchronous. When the service method returns, the callback has not been called yet. So the controller function will always return undefined (or the previous value of selectedItemsUpdate). The AJAX response needs to come back for the callback to be called. So the code should be:
$scope.param = function(){
items.getItems(function(data) {
$scope.selectedItemsUpdate = data;
});
}
And the HTML should be
<div data-dy-item data-items="selectedItemsUpdate"></div>
Of course, the params() function must be called at some time. It should probably be called when the controller is instantiated, or when some button is clicked.