Set controller property inside callback - ember.js

I have the following controller using ember.js and the ember-auth gem. This controller works but it sets the loginErrorproperty each time I get a sign in.
BaseApp.SignInController = Auth.SignInController.extend({
email: null,
password: null,
loginError: false,
signIn: function() {
this.registerRedirect();
Auth.signIn({
email: this.get('email'),
password: this.get('password')
});
this.set('loginError', true); // Sets correctly but each time
Auth.on('signInError', function() {
console.log("This is a signin error");
});
}
});
Obviously what I would like to do is set loginError to true inside the function that is called by Auth.on like this:
BaseApp.SignInController = Auth.SignInController.extend({
email: null,
password: null,
loginError: false,
signIn: function() {
this.registerRedirect();
Auth.signIn({
email: this.get('email'),
password: this.get('password')
});
Auth.on('signInError', function() {
this.set('loginError', true); // Doesn't set the controller's property
console.log("This is a signin error");
});
}
});
But this obviously doesn't work because the scope inside the callback is different. Maybe I'm missing something very basic. How can I make it work?

The context (ie. this) is different within the anonymous function you pass to the on method than in the controller. You can get around this by saving the context to a different variable within the closure.
var self = this;
Auth.on('signInError', function() {
self.set('loginError', true); // Should now set the controller's property
console.log("This is a signin error");
});

Related

Firebase error: The specified email address is invalid

I keep getting the error "The specified email address is invalid" in my Ember-Firebase app, even if I created an account just to test log in.
I'm wondering if it has to do with the way I'm passing information as a string?
initializer/emberfire.js
import Ember from 'ember';
import Firebase from 'firebase';
var session = Ember.Object.extend({
ref : new Firebase("https://nutella.firebaseio.com"),
addFirebaseCallback: function() {
var session = this;
var isNewUser = true;
this.get("ref").onAuth(function(authData) {
if (authData) {
session.set("isAuthenticated", true);
} else if (authData && isNewUser) {
session.get("ref").child("users").child(authData.uid).set({
provider: authData.provider,
name: getName(authData)
});
} else {
session.set("isAuthenticated", false);
}
});
}.on("init"),
createUser: function() {
var session = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
session.get('ref').createUser({
name: "",
email: "",
password: ""
},
function(error, userData) {
if (userData) {
resolve(userData.uid);
session.set("isNewUser", true);
} else {
reject(error);
}
});
});
},
application.js
import Ember from 'ember';
import Firebase from 'firebase';
var ref = new Firebase("https://nutella.firebaseio.com");
export default Ember.Route.extend({
actions: {
createUser: function() {
var controller = this;
controller.get('session').createUser().then(function(user) {
}, function() {
});
},
I'd really appreciate if you could point me in the right direction!
Passing a string shouldn't be a problem. Here are a couple suggestions:
(This may be obvious, but...) It seems like you're passing empty strings to createUser:
session.get('ref').createUser({
name: "",
email: "",
password: ""
},
Assuming that you removed the strings from the code on purpose, there is also the fact that you're passing Firebase.createUser() an extra argument, name.
In the .createUser() documentation, the arguments are listed as:
credentials Object
An object containing email and password attributes corresponding to the new user account.
onComplete Function
A callback function that will be called when the user account has been created. On failure, the first argument will be an Error object indicating the failure, with a machine-readable code attribute. On success, the first argument will be null, and the second argument will be an object containing attributes of the newly-created user, including the uid.
So, here is a revised version of your call to createUser():
session.get('ref').createUser({
email: "some#user.com",
password: "somepassword123"
},
If that doesn't do it, can you provide more info - where (line number) are you getting that error?
Hope that helps.

Ember-cli throwing Unexpected Token error

Undoubtedly this error is something easy for an ember expert to identify but thats not me so here it is
Ember-cli identifies blank space before this line as an unexpected token:
this.store = container.lookup('store:main');
/*global md5*/
import Ember from 'ember';
// Since I've defined my url in environment.js I can do this
import ENV from '../config/environment';
var ref = new window.Firebase(ENV.firebaseURL);
export default {
name: 'session',
// Run the initializer after the store is ready
after: 'store',
initialize: function(container, app) {
// session object is nested here as we need access to the container to get the store
var session = Ember.Object.extend({
// initial state
authed: false,
// get access to the ember data store
//Here is the offending line
this.store = container.lookup('store:main');
init: function() {
// on init try to login
ref.onAuth(function(authData) {
// Not authenticated
if (!authData) {
this.set('authed', false);
this.set('authData', null);
this.set('user', null);
return false;
}
// Authenticated
this.set('authed', true);
this.set('authData', authData);
this.afterAuthentication(authData.uid);
}.bind(this));
},
// Call this from your Ember templates
login: function(provider) {
this._loginWithPopup(provider);
},
// Call this from your Ember templates
logout: function() {
ref.unauth();
},
// Default login method
_loginWithPopup: function(provider) {
var _this = this;
// Ember.debug('logging in with popup');
ref.authWithOAuthPopup(provider, function(error, authData) {
if (error) {
if (error.code === "TRANSPORT_UNAVAILABLE") {
// fall-back to browser redirects, and pick up the session
// automatically when we come back to the origin page
_this._loginWithRedirect(provider);
}
} else if (authData) {
// we're good!
// this will automatically call the on ref.onAuth method inside init()
}
});
},
// Alternative login with redirect (needed for Chrome on iOS)
_loginWithRedirect: function(provider) {
ref.authWithOAuthRedirect(provider, function(error, authData) {
if (error) {
} else if (authData) {
// we're good!
// this will automatically call the on ref.onAuth method inside init()
}
});
},
// Runs after authentication
// It either sets a new or already exisiting user
afterAuthentication: function(userId) {
var _this = this;
// See if the user exists using native Firebase because of EmberFire problem with "id already in use"
ref.child('users').child(userId).once('value', function(snapshot) {
var exists = (snapshot.val() !== null);
userExistsCallback(userId, exists);
});
// Do the right thing depending on whether the user exists
function userExistsCallback(userId, exists) {
if (exists) {
_this.existingUser(userId);
} else {
_this.createUser(userId);
}
}
},
// Existing user
existingUser: function(userId) {
this.store.find('user', userId).then(function(user) {
_this.set('user', user);
}.bind(this));
},
// Create a new user
createUser: function(userId) {
var _this = this;
this.get('store').createRecord('user', {
id: userId,
provider: this.get('authData.provider'),
name: this.get('authData.facebook.displayName') || this.get('authData.google.displayName'),
email: this.get('authData.facebook.email') || this.get('authData.google.email'),
created: new Date().getTime()
}).save().then(function(user){
// Proceed with the newly create user
_this.set('user', user);
});
},
// This is the last step in a successful authentication
// Set the user (either new or existing)
afterUser: function(user) {
this.set('user', user);
}
});
// Register and inject the 'session' initializer into all controllers and routes
app.register('session:main', session);
app.inject('route', 'session', 'session:main');
app.inject('controller', 'session', 'session:main');
}
};
You're calling Ember.Object.extend with an Javascript Object literal what you are trying to do is invalid javascript syntax.
You'll probably want to stick that line in your init function.
init: function() {
//Here is the offending line
this.store = container.lookup('store:main');
...
When you get an invalid token error message you're writing something the javascript compiler doesn't understand.

ember-cli custom authenticator simple auth session authentication failed

What do I need to add to the code to initiate the sessionAuthenticationFailed(error). Right now it works when I have a successful login but I would like it also to show a message when when an incorrect username and/or password is entered.
here is what I have within authenticate in my custom authenticator
authenticate: function(credentials) {
var _this = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.post( _this.serverTokenEndpoint, {
email: credentials.identification,
password: credentials.password
}).then(function(response) {
Ember.run(function() {
resolve({ token: response.session.token });
});
}, function(xhr, status, error) {
var response = JSON.parse(xhr.responseText);
Ember.run(function() {
reject(response.error);
});
});
});
}
I would also like to show an error message. What do I need to put in my loginController.
The session's authenticate method returns a promise. You can attach a then to that and handle it accordingly in your controller, e.g.:
this.get('session').authenticate('authenticator', { … }).then(function() { /*success*/ }, function() { /* error */ });
or if you're using the LoginControllerMixin:
export Ember.Route.extend(LoginControllerMixin, {
actions: {
authenticate: function() {
this._super().then(function() { /*success*/ }, function() { /* error */ });
}
}
});
The sessionAuthenticationFailed should be called automatically anyway whenever authentication fails but if you want to e.g. display an error message when authentication fails etc. I'd use above approach.

Ember - How can I call the route's action from my controller

I'm using ember-simple-auth along with ember-validations to validate my user login credentials
in order to validate I "override" the login route's login action in controller.
The problem is that after validation I now wanna bubble up the action; however, since validate returns a promise I can't just simply return true.
I tried calling my route with this.get('target').send('login') but apparently it doesn't work.
I tried this.send('login') but this creates an infinite loop as the controller calls itself recursively.
Just use a different action name in the controller and call login there
actions: {
validate: function() {
var that = this;
return this.validate().then(function() {
that.send('login');
}, function() {
// report errors in an array
var errors = that.get('errors');
var fullErrors = [];
Object.keys(errors).forEach(function(val) {
if(errors[val] instanceof Array)
errors[val].forEach(function(msg) {
fullErrors.push([val, msg].join(" "));
});
});
that.set('fullErrors',fullErrors);
});
},
loginFailed: function(xhr) {
this.set('errorMessage', xhr.responseText);
}
}

Computed Property not firing

I have a computed property cookieToggle that I'm using in a LoginController. The basic idea is that it would observe the username and rememberMe fields and set or clear the username cookie as appropriate. Unfortunately when I update either of the dependant fields it never calls the cookieToggle function (as observed by the lack of the console message that every call should produce). My main question is: why not? My secondary question is: is this a reasonable use of Ember's computed property?
App.LoginController = Ember.ObjectController.extend({
CLIENT_ID: 1,
username: null,
password: null,
rememberMe: false,
cookieToggle: function() {
var rememberMe = this.get('rememberMe');
var username = this.get('username');
console.log("cookie toggle");
if (rememberMe) {
$.cookie('auth_username', username);
} else {
$.removeCookie('auth_username');
}
return rememberMe;
}.property('rememberMe','username'),
init: function() {
this._super();
if ($.cookie('auth_username')) {
this.set('username', $.cookie('auth_username'));
this.set('rememberMe', true);
}
},
loginUser: function() {
var router = this.get('target');
var data = this.getProperties('username', 'password', 'rememberMe');
var user = this.get('model');
$.post('/api/oauth/user_credentials', { username: data.username, password: data.password, client_id: this.get('CLIENT_ID') }, function(results) {
// App.AuthManager.authenticate(results.api_key.access_token, results.api_key.user_id);
console.log(results);
$.cookie('auth_user', results.user.id);
router.transitionTo('users/login');
});
}
});
A computed property is not the right decision in this case. You want to use an Observer. You even use this verb yourself, right? :-) Just change your declaration from property to observes :
cookieToggle: function() {
var rememberMe = this.get('rememberMe');
var username = this.get('username');
console.log("cookie toggle");
if (rememberMe) {
$.cookie('auth_username', username);
} else {
$.removeCookie('auth_username');
}
}.observes('rememberMe','username') // will fire every time when one of those properties change