In an Ember controller, I want to call my API to create a user and on success, transitionToRoute. This is what I currently want to work:
import ajax from "ic-ajax";
import Ember from "ember";
export default Ember.Controller.extend({
actions: {
createAndLoginUser: function() {
var user = { "user": this.getProperties("email", "name") };
ajax({ url: "api/users", type: "POST", data: user })
.then(transitionToHome);
}
}
});
var transitionToHome = function() {
this.transitionToRoute("home")
}
But when I place a debugger
in the method, this
is no longer the controller object and is out of scope to call transitionToRoute
.
I've only ever written hacky javascript, but I'm trying to learn core concepts and some frameworks. Is this the right way to use a promise? And is this the right place in Ember to put a transition?
Your problem has nothing to do with Ember or transitions; it's all about this
handling. The simplest solution is just
.then(transitionToHome.bind(this));
You could also consider putting transitionToHome
inside the controller as a method. Then, you could call it as in the following:
export default Ember.Controller.extend({
transitionToHome: function() { this.transitionToRoute("home"); },
actions: {
createAndLoginUser: function() {
var self = this;
var user = { "user": this.getProperties("email", "name") };
ajax({ url: "api/users", type: "POST", data: user })
.then(function() { self.transitionToHome(); });
}
}
});
This might be a simpler approach which is more readable and doesn't require reasoning about this
and using bind
(but does require using self
).
Outside the scope of your question, but some would say that route-related logic (including transitioning) logically belongs in the route, not the controller. If you agree, you could refactor the above to do a send
createAndLoginUser: function() {
var user = { "user": this.getProperties("email", "name") };
var self = this;
ajax({ url: "api/users", type: "POST", data: user })
.then(function() { self.send("goHome"); });
}
}
and then implement the goHome
action in your route. Or, you could implement goHome
in a higher-level route, even the application route, thus making it available from any controller or lower-level route.
Others might say that the ajax logic does not really belong here in the controller, and should rightfully be in a services layer, so
// services/user.js
export function createUser(data) {
return ajax({ url: "api/users", type: "POST", data: { user: data } });
}
// controller
import { createUser } from 'app/services/user';
export default Ember.Controller.extend({
createAndLoginUser: function() {
var data = this.getProperties("email", "name"));
var self = this;
createUser(data) . then(function() { self.send("goHome"); });
}
};
Using ES6 syntax, we can avoid the self
, simplifying a bit in the process:
createAndLoginUser: function() {
var data = this.getProperties("email", "name"));
var goHome = () => this.send("goHome");
createUser(data) . then(goHome);
}
Now this code is starting to look more semantic and readable.