Trying to access $scope.mySlot.id but it is undefined.
$scope.removeMe = function() {
var shouldRemove = confirm('Remove you from this field trip?');
if (shouldRemove) {
var data = null;
UserService.me().then(function(me){
var data = {userID: me.id, eventID: tripID}
console.log(data);
return data;
}).then (function(data){
var mySlot = GreenTripFilledSlotsFactory.get(data);
return mySlot;
}).then (function(mySlot) {
$scope.mySlot = mySlot;
console.log("this is $scope.mySlot: ");
console.log($scope.mySlot); //this shows up as a resource with proper values
console.log("this is $scope.mySlot.id: ")
console.log($scope.mySlot.id); //this is undefined
}).then (function(success){
return $scope.mySlot.$delete(); // this isn't working'
}).then(function(success){
console.log('mySlot deleted');
route.reload();
}).catch(function(error){
console.log(error);
})
}
};
In the console.logs $scope.mySlot is shown as a resource and it does list the values of it. But I'm confused why $scope.mySlot.id is undefined.
FACTORIES:
.factory('GreenTripSlotsFactory', ['$resource', function($resource) {
return $resource('/api/GreenTripSlots/:id/', {id: '#id' }, {
update: {method: 'PUT' }
});
}])
.factory('GreenTripFilledSlotsFactory', ['$resource',
function($resource) {
return $resource('/api/GreenTripSlots/:userID/:eventID/:slotID',
{id: '#id' }, {
update: {method: 'PUT' }
});
}])
BACKEND contollers:
// = /api/GreenTripSlots/:userID/:eventID
router.route('/:userID/:eventID')
.get(function(req,res) {
procedures.procGetSlotByUserAndTrip(req.params.userID,
req.params.eventID).then(function(greenTripUserSlot){
res.send(greenTripUserSlot);
}, function(err) {
console.log(err);
res.sendStatus(500);
})
})
// = /api/GreenTripSlots:/userID/:eventID/:slotID
router.route('/:userID/:eventID/:slotID')
.get(function(req,res) {
procedures.procGetSlotByUserAndTrip(req.params.userID,
req.params.eventID).then(function(greenTripUserSlot){
res.send(greenTripUserSlot);
}, function(err) {
console.log(err);
res.sendStatus(500);
})
})
.delete(function(req, res){
procedures.procRemoveMe(req.params.slotID).then(function(){
res.sendStatus(204);
}, function(err) {
console.log(err);
res.sendStatus(500);
});
})
Backend Procedures:
exports.procGetSlotByUserAndTrip = function(userID, eventID) {
return db.fnRow('procGetSlotByUserAndTrip', [userID, eventID])
}
exports.procRemoveMe = function(slotID) {
return db.fnEmpty('procRemoveMe', [slotID])
SQL Stored Procedure for Get:
CREATE DEFINER=`CharleyHannah`#`localhost` PROCEDURE
`procGetSlotByUserAndTrip`(pUserId INT, pEventId INT)
BEGIN
SELECT *
FROM userEvents u
WHERE u.userID = pUserId & u.eventID = pEventId;
END
SQL Stored Procedure for delete:
CREATE DEFINER=`CharleyHannah`#`localhost` PROCEDURE
`procRemoveMe`(pSlotId int)
BEGIN
DELETE
FROM userEvents
WHERE id = pSlotId;
END
Your function GreenTripFilledSlotsFactory.get(data); returns a promise. You can write something like that:
var _promise = GreenTripFilledSlotsFactory.get(data);
_promise.then(function(res) {
$scope.mySlot = res;
console.log($scope.mySlot.id); //should display your value now
});
In the res Variable your object is stored.
You assign userToRemove outside the promise then and it's executed before $scope.ME assingning.
Instead of using the factories, I had success in just using $http.get and $http.delete requests:
$scope.removeMe = function() {
var shouldRemove = confirm('Remove you from this field trip?');
if (shouldRemove) {
var data = null;
UserService.me().then(function(me){
var data = {eventID: tripID, userID: me.id}
console.log(data);
return data;
}).then (function(data){
var mySlot = $http.get('/api/GreenTripSlots/' + data.eventID + '/' + data.userID);
console.log(mySlot);
return mySlot;
}).then (function(mySlot) {
var slotToDelete = mySlot.data;
console.log(slotToDelete);
console.log(slotToDelete.id)
return slotToDelete;
}).then (function(slotToDelete){
var slotID = slotToDelete.id;
$http.delete('/api/GreenTripSlots/delete/' + slotID);
console.log('deleted successfully')
$route.reload();
}).catch(function(error){
console.log(error);
})
}
};
}])
I would like to get the currently loged in username so i can display it. But i dont know how to do it ? Any ideas ? I am using authservice Here is my angular controller in which i would like to get the username.
myApp.controller('meetupsController', ['$scope', '$resource', function ($scope, $resource) {
var Meetup = $resource('/api/meetups');
$scope.meetups = []
Meetup.query(function (results) {
$scope.meetups = results;
});
$scope.createMeetup = function () {
var meetup = new Meetup();
meetup.name = $scope.meetupName;
meetup.$save(function (result) {
$scope.meetups.push(result);
$scope.meetupName = '';
});
}
}]);
my main angular controller code
var myApp = angular.module('myApp', ['ngResource', 'ngRoute']);
myApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/main.html',
access: {restricted: true}
})
.when('/api/meetups', {
templateUrl: 'partials/main.html',
access: {restricted: true}
})
.when('/login', {
templateUrl: 'partials/login.html',
controller: 'loginController',
access: {restricted: false}
})
.when('/prive', {
templateUrl: 'partials/prive.html',
controller: 'userController',
access: {restricted: true}
})
.when('/logout', {
controller: 'logoutController',
access: {restricted: true}
})
.when('/register', {
templateUrl: 'partials/register.html',
controller: 'registerController',
access: {restricted: false}
})
.when('/one', {
template: '<h1>This is page one!</h1>',
access: {restricted: true}
})
.when('/two', {
template: '<h1>This is page two!</h1>',
access: {restricted: false}
})
.otherwise({
redirectTo: '/'
});
});
myApp.run(function ($rootScope, $location, $route, AuthService) {
$rootScope.$on('$routeChangeStart',
function (event, next, current) {
AuthService.getUserStatus()
.then(function(){
if (next.access.restricted && !AuthService.isLoggedIn()){
$location.path('/login');
$route.reload();
}
});
});
});
myApp.controller('meetupsController', ['$scope', '$resource', function ($scope, $resource) {
var Meetup = $resource('/api/meetups');
$scope.meetups = []
Meetup.query(function (results) {
$scope.meetups = results;
});
$scope.createMeetup = function () {
var meetup = new Meetup();
meetup.name = $scope.meetupName;
meetup.$save(function (result) {
$scope.meetups.push(result);
$scope.meetupName = '';
});
}
}]);
my second angular code :
var app = angular.module('myApp');
app.controller('loginController',
['$scope', '$location', 'AuthService',
function ($scope, $location, AuthService) {
$scope.login = function () {
// initial values
$scope.error = false;
$scope.disabled = true;
// call login from service
AuthService.login($scope.loginForm.username, $scope.loginForm.password)
// handle success
.then(function () {
$location.path('/');
$scope.disabled = false;
$scope.loginForm = {};
})
// handle error
.catch(function () {
$scope.error = true;
$scope.errorMessage = "Invalid username and/or password";
$scope.disabled = false;
$scope.loginForm = {};
});
};
$scope.posts = [];
$scope.newPost = {created_by: '', text: '', created_at: ''};
$scope.post = function(){
$scope.newPost.created_at = Date.now();
$scope.posts.push($scope.newPost);
$scope.newPost = {created_by: '', text: '', created_at: ''};
};
}]);
app.controller('logoutController',
['$scope', '$location', 'AuthService',
function ($scope, $location, AuthService) {
$scope.logout = function () {
// call logout from service
AuthService.logout()
.then(function () {
$location.path('/login');
});
};
$scope.gotoregister = function () {
$location.path('/register');
};
$scope.gotoprive = function () {
$location.path('/prive');
};
}]);
app.controller('registerController',
['$scope', '$location', 'AuthService',
function ($scope, $location, AuthService) {
$scope.register = function () {
// initial values
$scope.error = false;
$scope.disabled = true;
// call register from service
AuthService.register($scope.registerForm.username, $scope.registerForm.password)
// handle success
.then(function () {
$location.path('/login');
$scope.disabled = false;
$scope.registerForm = {};
})
// handle error
.catch(function () {
$scope.error = true;
$scope.errorMessage = "Something went wrong!";
$scope.disabled = false;
$scope.registerForm = {};
});
};
}]);
and my services
angular.module('myApp').factory('AuthService',
['$q', '$timeout', '$http',
function ($q, $timeout, $http) {
// create user variable
var user = null;
// return available functions for use in the controllers
return ({
isLoggedIn: isLoggedIn,
getUserStatus: getUserStatus,
login: login,
logout: logout,
register: register
});
function isLoggedIn() {
if(user) {
return true;
} else {
return false;
}
}
function getUserStatus() {
return $http.get('/user/status')
// handle success
.success(function (data) {
if(data.status){
user = true;
} else {
user = false;
}
})
// handle error
.error(function (data) {
user = false;
});
}
function login(username, password) {
// create a new instance of deferred
var deferred = $q.defer();
// send a post request to the server
$http.post('/user/login',
{username: username, password: password})
// handle success
.success(function (data, status) {
if(status === 200 && data.status){
user = true;
deferred.resolve();
} else {
user = false;
deferred.reject();
}
})
// handle error
.error(function (data) {
user = false;
deferred.reject();
});
// return promise object
return deferred.promise;
}
function logout() {
// create a new instance of deferred
var deferred = $q.defer();
// send a get request to the server
$http.get('/user/logout')
// handle success
.success(function (data) {
user = false;
deferred.resolve();
})
// handle error
.error(function (data) {
user = false;
deferred.reject();
});
// return promise object
return deferred.promise;
}
function register(username, password) {
// create a new instance of deferred
var deferred = $q.defer();
// send a post request to the server
$http.post('/user/register',
{username: username, password: password})
// handle success
.success(function (data, status) {
if(status === 200 && data.status){
deferred.resolve();
} else {
deferred.reject();
}
})
// handle error
.error(function (data) {
deferred.reject();
});
// return promise object
return deferred.promise;
}
}]);
So this should probably work, maybe you will need to make some small adjustments because i don't know how exactly is your app structured, but this will work.
First you need to change your AuthService to look like this
angular.module('myApp').factory('AuthService',
['$q', '$timeout', '$http',
function ($q, $timeout, $http, $cookies) {
// create user variable
var user = null;
// we must create authMemberDefer var so we can get promise anywhere in app
var authenticatedMemberDefer = $q.defer();
// return available functions for use in the controllers
return ({
isLoggedIn: isLoggedIn,
getUserStatus: getUserStatus,
login: login,
logout: logout,
register: register,
getAuthMember: getAuthMember,
setAuthMember: setAuthMember
});
function isLoggedIn() {
if(user) {
return true;
} else {
return false;
}
}
//this is function that we will call each time when we need auth member data
function getAuthMember() {
return authenticatedMemberDefer.promise;
}
//this is setter function to set member from coockie that we create on login
function setAuthMember(member) {
authenticatedMemberDefer.resolve(member);
}
function getUserStatus() {
return $http.get('/user/status')
// handle success
.success(function (data) {
if(data.status){
user = true;
} else {
user = false;
}
})
// handle error
.error(function (data) {
user = false;
});
}
function login(username, password) {
// create a new instance of deferred
var deferred = $q.defer();
// send a post request to the server
$http.post('/user/login',
{username: username, password: password})
// handle success
.success(function (data, status) {
if(status === 200 && data.status){
user = true;
deferred.resolve();
//**
$cookies.putObject('loginSession', data);
// here create coockie for your logged user that you get from this response, im not sure if its just "data" or data.somethingElse, check you response you should have user object there
} else {
user = false;
deferred.reject();
}
})
// handle error
.error(function (data) {
user = false;
deferred.reject();
});
// return promise object
return deferred.promise;
}
function logout() {
// create a new instance of deferred
var deferred = $q.defer();
// send a get request to the server
$http.get('/user/logout')
// handle success
.success(function (data) {
user = false;
deferred.resolve();
//on log out remove coockie
$cookies.remove('loginSession');
})
// handle error
.error(function (data) {
user = false;
deferred.reject();
});
// return promise object
return deferred.promise;
}
function register(username, password) {
// create a new instance of deferred
var deferred = $q.defer();
// send a post request to the server
$http.post('/user/register',
{username: username, password: password})
// handle success
.success(function (data, status) {
if(status === 200 && data.status){
deferred.resolve();
} else {
deferred.reject();
}
})
// handle error
.error(function (data) {
deferred.reject();
});
// return promise object
return deferred.promise;
}
}]);
after that changes in authService, you must make this on your app run, so each time application run (refresh) it first check coockie to see if there is active session(member) and if there is it will set it inside our AuthService.
myApp.run(function($rootScope, $location, $route, AuthService, $cookies) {
$rootScope.$on('$routeChangeStart',
function(event, next, current) {
if ($cookies.get('loginSession')) {
var session = JSON.parse($cookies.get('loginSession'));
AuthService.setAuthMember(session);
} else {
$location.path('/login');
}
});
});
And simply anywhere where you want to get auth member you have to do this, first include in your controller/directive AuthService and do this
AuthService.getAuthMember().then(function(member){
console.log(member);
//here your member should be and you can apply any logic or use that data where u want
});
I hope this helps you, if you find any difficulties i'm happy to help
just a demo example
in login controller
var login = function(credentials) {
AuthService.login(credentials).then(function(result) {
var user = result.data;
AuthService.setCurrentUser(user);
$rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
}).catch(function(err) {
if (err.status < 0) {
comsole.error('Please check your internet connection!');
} else {
$rootScope.$broadcast(AUTH_EVENTS.loginFailed);
}
});
};
in AuthService
.factory('AuthService', function($http, $cookies, BASE_URL) {
var service = {
login: function(formdata) {
return $http.post(BASE_URL + '/login', formdata);
},
setCurrentUser: function(user) {
$cookies.putObject('currentUser', user);
},
isAuthenticated: function() {
return angular.isDefined($cookies.getObject('currentUser'));
},
getFullName: function() {
return $cookies.getObject('currentUser').firstName + ' ' + $cookies.getObject('currentUser').lastName;
}
}
return service;
});
in the controller which attached with your dashboard view
$scope.$watch(AuthService.isAuthenticated, function(value) {
vm.isAuthenticated = value;
if (vm.isAuthenticated) {
vm.fullName = AuthService.getFullName();
vm.currentUser = AuthService.getCurrentUser();
}
});
There are few methods how you can get currently logged user, it mostly depends on you app structure and API, you probably should have API end point to get authenticated member and that call is made on each app refresh.
Also if you can show us your authservice.
Edit:
Also on successful login you can store information about logged user in coockie like this
function doLogin(admin) {
return authMemberResources.login(details).then(function(response) {
if (response) {
$cookies.putObject('loginSession', response);
} else {
console.log('wrong details');
}
});
So basically you can use angularjs coockies service and make loginSession coockie like that, and on app refresh or anywhere where you need logged user info, you can get that like this:
if ($cookies.get('loginSession')) {
var session = JSON.parse($cookies.get('loginSession'));
console.log(session);
}
.factory('AuthService', function($http, $cookies, BASE_URL) {
var service = {
login: function(formdata) {
return $http.post(BASE_URL + '/login', formdata);
},
setCurrentUser: function(user) {
$cookies.putObject('currentUser', user);
},
isAuthenticated: function() {
return angular.isDefined($cookies.getObject('currentUser'));
},
getFullName: function() {
return $cookies.getObject('currentUser').firstName + ' ' + $cookies.getObject('currentUser').lastName;
},
getAuthenticatedMember: function() {
if ($cookies.get('currentUser')) {
return JSON.parse($cookies.get('currentUser'));
}
}
}
return service;
});
That should work, i added new function getAuthenticatedMember and you can use it where you need it. And you can use it like this:
$scope.$watch(AuthService.isAuthenticated, function(value) {
vm.isAuthenticated = value;
if (vm.isAuthenticated) {
vm.currentUser = AuthService.getAuthenticatedMember();
}
});
I my Node backend have the following end-point:
usersRoute.get('/get', function(req, res) {
//If no date was passed in - just use todays date
var date = req.query.date || dateFormat(new Date(), 'yyyy-mm-dd'),
search = req.query.search;
users.getAllUsers(date, search)
.then(function(results) {
res.json(results);
}, function(err) {
res.status(500).json({
success: false,
message: 'Server error.',
data: []
});
});
});
I have changed my sql table name to something else to trigger the function(err){} part
When I use this in my service it looks like this:
function getUsers(date, search) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(getData)
.catch(handleErr);
function getData(response) {
return response.data;
}
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
}
}
Knowing the server will return an http status code 500, I thought it would go right to the catch block. But it also returns the data /which is undefined in the then block
I use my service in my controller like this:
function getUsers(date, search) {
isAdmin();
vm.loading = true;
vm.filteredUsers = [];
return UsersService.getUsers(date, search).then(function(data) {
vm.loading = false;
allUsers = data || [];
vm.filteredUsers = allUsers.slice(0, 50);
vm.distribution = UsersService.getDistribution(allUsers);
return vm.filteredUsers;
});
}
My problem is, since the then part is triggered in my service. I'm trying to slice undefined
My question is: What are som best practices when it comes to this sort of pattern.
The problem is that your catching the error from your API and then returning the promise created by .catch.
Quick example
promise.then(function(data) {
throw 'Some error';
}).catch(function (err) {
console.log(err) // will output 'Some error'
}).then(function () {
// This will run even though we have a catch before
});
So how can we prevent the .then it's easy we throw an error inside the .catch
promise.then(function(data) {
throw 'Some error';
}).catch(function (err) {
console.log(err) // will output 'Some error'
throw 'You shall not pass'
}).then(function () {
// This will not run
});
So in your case you have two options, one throw an error as I said or two inject the $q service into your service:
function getUsers(date, search) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(getData)
.catch(handleErr);
function getData(response) {
return response.data;
}
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
return $q.reject(err);
}
}
You could do something like that
function getUsers(date, search, cb) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(cb)
.catch(handleErr);
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
}
}
And then in your controller
UsersService.getUsers(date, search, function(data) {
vm.loading = false;
allUsers = data || [];
vm.filteredUsers = allUsers.slice(0, 50);
vm.distribution = UsersService.getDistribution(allUsers);
});
In this git issue AngularFire disabled the auto-login functionality associated with $createUser. (The docs are outdated.)
So what's the best practice / cleanest way to create a user and then log them in?
app.factory('Auth', function($firebaseSimpleLogin, FIREBASE_URL, $rootScope) {
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
register: function (user) {
return auth.$createUser(user.email, user.password);
},
login: function (user) {
return auth.$login('password', user);
},
...
Note: $createUser returns a md5 hash but $login uses plaintext password.
I'm new to promises. Thanks!
I didn't realize what Kato meant. But now that I understand promises the solution is pretty straight forward:
register: function (user) {
return auth.$createUser(user.email, user.password)
.then(function() {
return auth.$login('password', user);
});
},
I think this should do it. You have to use q or inject angular.$q.
app.factory('Auth', function($firebaseSimpleLogin, FIREBASE_URL, $rootScope) {
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseSimpleLogin(ref);
var deferred = Q.defer(); // from Q lib
// var deferred = $q.defer(); //angularjs q
var Auth = {
register: function (user) {
auth.$createUser(user.email, user.password)
.then(function(result) {
deferred.notify('user created.'); // optional notify progress
return auth.$login('password', user); // return a new promise for chaining.
},
function(reason) {
// createUser failed
deferred.reject(reason);
})
.then(function(result) {
// resolve the login promise return from above
deferred.resolve(result);
},
function(reason) {
// login failed
deferred.reject(reason);
});
return deferred;
},
login: function (user) {
return auth.$login('password', user);
},
...
I've got a single page which is an account settings page. In it, I allow my users to update their avatar (if they've attached an image), change their email (if it has been changed from the original), and change their name and password.
Right now, I'm using async's waterfall method, but am swapping out async for Q since I prefer the syntax (and api). I'm wondering if this is the way that I should be using Q in replacement of async's waterfall.
I'm doing something like this:
exports.settingsAccountPOST = function(req, res) {
var doesEmailExist = function() {
var deferred = Q.defer();
User.findByEmail({
email: req.body.email
}, function(err, user) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(user);
}
});
return deferred.promise;
};
var updateEmail = function(email) {
var deferred = Q.defer();
User.updateEmail({
userId : req.session.user.id,
email : req.body.email
}, function(err, updated) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(updated);
}
});
return deferred.promise;
};
var updateName = function() {
var deferred = Q.defer();
if (req.body.name) {
User.updateName({
userId: req.session.user.id,
name: req.body.name
}, function(err, updated) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(updated);
}
});
return deferred.promise;
}
};
doesEmailExist().then(function(email) {
if (!email) {
return(updateEmail(email));
}
}).then(function() {
return(updateName())
}).then(function() {
res.redirect('/account')
});
};
Say that there is an error with the email address being used. Is there a way to "pass" it to the final call? Use case: Updated password properly, but email update didn't work, so I want to show a session flash to the user telling them they updated their password properly, but there was an issue with updating their email.
I was looking in the docs and it seems I may need to use:
.fin(function () {
});
Is this correct? If so, what should I be passing into that? Just push to an object the error that occurred within the chain and then loop through all errors and display them to the user? Or just return immediately and display the error?
If you are using Q.defer you are generally doing something wrong.
var findByEmail = Q.nbind(User.findByEmail, User);
var updateEmail = Q.nbind(User.updateEmail, User);
var updateName = Q.nbind(User.updateName, User);
//later on...
exports.settingsAccountPOST = function (req, res) {
findByEmail({
email: req.body.email
})
.then(function (user) {
if (!user) {
return updateEmail({
userId: req.session.user.id,
email: req.body.email
});
}
})
.then(function () {
return updateName({
userId: req.session.user.id,
name: req.body.name
})
})
.then(function () {
res.redirect("/account");
})
.catch(function(e){
//Handle any error
});
};