Transitioning to another route from within a controller

Is there a way to programatically transition to a different route from within the controller?

Yes, controller.transitionToRoute() and controller.replaceRoute(). Source here.

2 Likes

Thanks. I tried that but, keep getting this error:

Uncaught TypeError: Cannot read property 'transitionToRoute' of null libs.js:27095
Ember.ControllerMixin.reopen.transitionToRoute libs.js:27095
App.VisitorsController.Ember.ArrayController.extend.actionClick scripts.js:520
Ember.ControllerMixin.Ember.Mixin.create.send libs.js:14749
(anonymous function) libs.js:26752
(anonymous function) libs.js:6562
Ember.handleErrors libs.js:2613
invoke libs.js:6560
tryable libs.js:6749
Ember.tryFinally libs.js:3304
Ember.run libs.js:6753
ActionHelper.registeredActions.(anonymous function).handler libs.js:26750
(anonymous function) libs.js:16090
Ember.handleErrors libs.js:2613
(anonymous function) libs.js:16082
p.event.dispatch jquery.min.js:2
g.handle.h 
1 Like

Can you post some code? In views you have to access the controller using get('controller') because controller is a computed property.

From within a controller you can use this.transitionToRoute('route')

2 Likes

Has anyone found a solution this? Having the same issue.

@bradurani can you post a snippet the code. Either you’re in a function where the context of this is not the controller or something funky is going on.

It was because of some other goofiness I was doing. Got it handled.

Hello.

I am hijacking this thread for a while - hope you don’t mind! =)

Inside a controller, I am saving a record and then, much like the OP wanted to, I am transitioning to a route:

export default Ember.ArrayController.extend({
    onSuccessfulSave : function() {
        this.transitionToRoute('blog');
    },

    onFailedSave : function() {
        // Handle failed save
    },

    actions : {
        save : function() {
            
            // Other, unrelated code
            
            blogpost.save().then(this.onSuccessfulSave.bind(this), this.onFailedSave.bind(this));
        }
    }
});

However, after reading some posts on the web (mainly this one) it seems to me this might not be the best way to go about it, since it goes against the Ember way of doing things.

Judging from the first (the accepted) answer in that SO thread, it would be wrong to redirect from the controller to a route, or even saving the record in the controller at all. So should CRUD functionality etc be handled in the route?

For me (comming from ASP.NET MVC), the controller would be the natural place to do something like this. As I Understand it, a controller in Ember is something totally different, and should mainly concern itself with non-persistent and display-only-related data.

So, in short: is it considered good practise to save models and/or redirect to a route in a controller?

Thanks in adavance!

I think best practice is to handle data persistence on the router.

Disclaimer: I am new to using Ember!

Thanks for your answer, jsonmit. There is still some questions that I would like to get cleared out.

For example, this tutorial uses an action on the controller to persist a data record, which suggests this is the way to do it, since the tutorial is a part of the official ember documentation.

Also, the default behaviour of Ember (correct me if I’m wrong, cannot find the source now) is to first look for an aciton on the controller, and then (if it wasn’t found), look for the same acion on the route, suggesting a controller would be the place to put actions. Ofcourse, this doesn’t mean that one should automatically perform data persistence on the controller, but in my mind, the default behaviour of a framework is often time the more correct behaviour.

Another thing that I is unclear to me is that when I have this code:

Template:

<h2>New post</h2>

<form {{action save on="submit"}}>
    <label>Title</label>
        {{input type="text" value=title placeholder="title" id="title"}}

    <label>Text</label>

    {{textarea value=text placeholder="text" id="text"}}

    <button>Post</button>
</form>

Controller:

export default Ember.Controller.extend({
    actions : {
        save : function() {
            Ember.Logger.log('title:', this.title);
            Ember.Logger.log('text:', this.text);
            Ember.Logger.log('get title:', this.get('title'));
            Ember.Logger.log('get text:', this.get('text'));
        }
   }
});

Route:

export default Ember.Route.extend({
    actions : {
        save : function() {
            Ember.Logger.log('title:', this.title);
            Ember.Logger.log('text:', this.text);
            Ember.Logger.log('get title:', this.get('title'));
            Ember.Logger.log('get text:', this.get('text'));
        }
   }
});

I get the output:

Controller

title: a title.
text: a text
get title: a text
get text: a title

Router:

title: undefined
text: undefined
get title: undefined
get text: undefined

Which, to mee, suggests that the controller is the place to handle input data, since it has direct access to that data, while the route does not (would have to use Jquery or plain javascript to fetch it from the DOM as far as I can tell)

To access input data on the router I have tried binding a model with:

model : {
    return this.store.create('blogpost', { title: '', test: '' }
}

to use model.attribute for databinding in the template, and then accessing the values in the router that way, but that didn’t work either :expressionless:

So, the questions I have is (again) should I use the router for persisting data (and other CRUD functionality)? And if so, should I use a method on the controller for input validation etc and then pass the data forward to a method on the router where it gets persisted? Because I guess input validation etc. should not be in the router, right?

Sorry for the long post and thanks in advance! :slight_smile:

*Edit: formatiing for readability

@ggnore_alan_smithee you need to pass the model instance through the action if you want to access it on the controller. Or, you can always do this.controller.get(‘model.propertyName’) or if your controller is an Ember.ObjectController this.controller.get(‘propertyName’);

Example of both: Ember Latest - JSFiddle - Code Playground

@jsonmit

Thanks a lot for your help! I have gotten things to work now :slight_smile:

The only thing that is still a bit wierd is that in order to access the model attributes in the template I had to explicitly write model.title and model.text:

{{input type="text" value=model.title placeholder="title" id="title"}}
{{textarea value=model.text placeholder="text" id="text"}}

Would that be because I am routing with ‘route’ instead of ‘resource’ ?

this.resource('blog', function() {
    this.route('post', { path: '/:id' });
    this.route('new', { path: '/new' });
});

Everything else seems to be identical with your jsfiddle.

Again, thanks a bunch!

Make sure your controller is an Ember.ObjectController and not an Ember.Controller

Cheers! Thanks for all the help!