As I understand from the documentation a Service is basically a singleton object used to provide services to other objects through the application lifecycle. I have a user management service which I use to save an authentication token after the user logs in using the route /users/login
. But transitioning to another route (/composer
for instance) causes the service instance to be recreated and hence it loses all the stored data. Doesn't this contradict the fact that it should live as long as the application does or do I have a wrong of idea this whole lifecycle thingy?
I'm injecting the service in all my routes as below:
authenticationService: Ember.inject.service('authentication-service'),
The service itself is only a set of getters and setters:
import Ember from 'ember';
export default Ember.Service.extend({
currentUser: undefined,
jwtToken: undefined,
// ================================================================================================================ \\
// ================================================================================================================ \\
// ================================================================================================================ \\
setCurrentUser(user) {
this.currentUser = user ;
},
getCurrentUser() {
return this.currentUser ;
},
isLoggedIn() {
return Boolean(this.currentUser) ;
},
getJwtToken() {
return this.jwtToken ? this.jwtToken : '' ;
},
setJwtToken(jwtToken) {
this.jwtToken = jwtToken ;
}
});
Here is how the login token is handled:
actions: {
onSubmitLoginForm() {
if (!this.validateLoginForm()) {
return ;
}
var self = this ;
Ember.$.post('login/', {
'username': this.controller.get('username'),
'password': this.controller.get('password'),
'email': this.controller.get('email'),
}, function(data) {
console.log(data) ;
if (data['success'] === 'Ok') {
self.get('authenticationService').setJwtToken(data['auth']['jwt']) ;
var user = self.get('store').createRecord('user', {
username: data['auth']['user']['username'],
email : data['auth']['user']['email'],
mongoId : data['auth']['user']['id']['$oid'],
}) ;
self.get('authenticationService').setCurrentUser(user) ;
self.transitionTo('home') ;
console.log('logged in') ;
console.log(self.get('authenticationService').getJwtToken()) ;
console.log(self.get('authenticationService').getCurrentUser()) ;
console.log(self.get('authenticationService').isLoggedIn()) ;
} else {
self.transitionTo('error') ;
}
}) ;
},
}
I'm not looking for suggestions on using some other means of persistence such as IndexedDB; I'm willing to understand how this thing actually works so any explanation is appreciated.
Yes, you understand it right - service is a singletone and I can assure you that service persists its state between trasitions. But to make a transition, you must use link-to
helper. If you are changing url manually, you reloading your app instead of transitioning. And app reload of course causes state reset. You should use any available kind of storage to persist state between page reloads. It may be local storage, session storage, cookies etc.
Also, in Ember we don't use such code: this.currentUser = user ;
on Ember objects. We use this.set('currentUser', user);
instead. Otherwise Ember would not be able to rerender templates, update computed properties and work properly.
And finally, you shouldn't build auth solution from zero. It's very hard and complex thing to do. Instead, you can use ember-simple-auth addon and build authentication process on top of it. It will be much easier and result will be more reliable.