Skip to content
This repository

Controller instances not available in connectOutlets of root state. #941

wants to merge 2 commits into from

8 participants

Joshua Borton Peter Wagenet Justin Brown Don't Add Me To Your Organization a.k.a The Travis Bot Tom Dale Trek Glowacki Alex Matchneer Yehuda Katz
Joshua Borton

I'm not sure if this is intended, but controller instances are not available in the root state when the connectOutlets event is fired. This fiddle demonstrates.

Joshua Borton

The cause of this is due to Ember.StateManager automatically transitioning to the initialState upon creation. This triggers connectOutlets before injections happen.

Peter Wagenet

This seems like it's worth fixing but I would like to see what @tomdale and @wycats think.

Justin Brown
jbrown commented June 06, 2012

:+1: I worked around this by using a binding...

// initialState
connectOutlets: (router) ->
  rootView = Ember.ContainerView.create
    currentViewBinding: 'App.stateManager.applicationController.view'

Justin Brown
jbrown commented June 06, 2012

@digitaltoad What are you trying to do in connectOutlets of the root state? None of the test cases show connectOutlets on the root state. I'm not so sure that's the convention even though the original gist shows it done that way.

Joshua Borton

Sorry, I should have added a test for that as well. I've been going by the original gist. In current apps, instead of placing setup code in the root connectOutlets, I've created a single state inside root that would house the rest of my app states so that I would have access to the controllers there. This seemed like the way root was supposed to work. I'm not sure of a better way to defer the start of the router without the flag that I've inserted that wouldn't break any apps that assumed the router would automatically transition to the root state.

Justin Brown
jbrown commented June 06, 2012

Okay, disregard my first comment. I figured all of this out. I made you a gist. Let me know if that helps.

Joshua Borton

My problem arises from an example where the page is loaded at a state. For instance, I've extracted the navbar area. Where would the setup go for this. If the app loads at the home state, everything is fine. If the app loads at the profile state, the navbar is never loaded. Would the navbar have to be connected in every state or is there just a better way of handling this? This might of course just be a convention issue.

Justin Brown
jbrown commented June 06, 2012

You're not gaining anything by using connectOutlets for that. The real power of connectOutlet is passing a context in. A navbar likely has no context. If any part of it is dynamic, you probably want to just bind to something on applicationController, or have your own navbarController. Just use the Handlebars view helper. see here

Does that make sense?

Joshua Borton

This does indeed make sense. I had gone down the route of using a view helper before I learned about outlets. However, the question remains, if connectOutlets is still fired in the root state, should everything be wired and ready at that point?

Peter Wagenet

@digitaltoad This doesn't merge cleanly. Do you mind rebasing?

Joshua Borton
Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged 20d17d2 into d71677b).

Peter Wagenet

This looks good and would solve some annoyances for me as well. @wycats, @tomdale, what do you guys think?

Tom Dale

I agree that this is an important fix, but I think this hacks around the problem instead of addressing the core issue. Instead of special-casing the router to not automatically transition into the initialState, we should just make sure that the initialState's connectOutlets call back doesn't happen until the state manager has finished initializing.

Peter Wagenet

@tomdale So are you suggesting we delay the transitionEvent? This seems like you run into the same problem.

Joshua Borton

I had tried to figure out a way to do this without a hack. Maybe if I revisit I can come up with something else. My first thought was indeed to only fire the initial transitionEvent after the state manager was completely initialized (including injections).

Peter Wagenet

To clarify, both the initialState and the transitionEvent (connectOutlets) are handled by the StateManager class. Wherever we make the change, we're going to have to "hack" around it in the router. Delaying the initialState makes sense to me since the router really doesn't get kicked off until the first route call.

Trek Glowacki
trek commented July 09, 2012

I wanted to use connectOutlets on root state for an identical reason: setting up other main areas of the app that get their own controllers. For now, I'm doing

 {{view App.SearchView controllerBinding="App.router.searchController"}}

But I'd like to see this usage of connectOutlets in 1.0. @tomdale you seem OK statemanger being changed so the transition can be delayed?

Trek Glowacki
trek commented July 17, 2012

Sorry to pester, but were we going to pull this PR or wait to implement @tomdale's suggestion of making a statemanager's root state transitionEvent not trigger until the manager is done being initialized?

Alex Matchneer

What's the state of this? I'm using trek's hack in the meantime but would be nice to reference at least applicationController in the root connectOutlets

Peter Wagenet

Since routing is something that's been design by @wycats and @tomdale I'd really like to hear their opinion on the correct solution for this.

Yehuda Katz

A solution to this is definitely desired and is targeted for Router v2.

Yehuda Katz wycats closed this October 09, 2012
Jakub Nieznalski knusul referenced this pull request from a commit October 28, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
3  packages/ember-application/lib/system/application.js
@@ -107,7 +107,7 @@ Ember.Application = Ember.Namespace.extend(
107 107
         namespace = this, controller, name;
108 108
109 109
     if (!router && Ember.Router.detect(namespace['Router'])) {
-      router = namespace['Router'].create();
+      router = namespace['Router'].create({ autoInitialState: false });
111 111
       this._createdRouter = router;
112 112
113 113
@@ -166,6 +166,7 @@ Ember.Application = Ember.Namespace.extend(
166 166
167 167
168 168
+    router.initialize();
169 170
170 171
     location.onUpdateURL(function(url) {
171 172
12  packages/ember-states/lib/state_manager.js
@@ -373,6 +373,8 @@ require('ember-states/state');
373 373
 Ember.StateManager = Ember.State.extend(
374 374
 /** @scope Ember.StateManager.prototype */ {
375 375
+  autoInitialState: true,
376 378
377 379
     When creating a new statemanager, look for a default state to transition
378 380
     into. This state can either be named `start`, or can be specified using the
@@ -383,6 +385,16 @@ Ember.StateManager = Ember.State.extend(
383 385
384 386
     set(this, 'stateMeta', Ember.Map.create());
385 387
+    var initialState = get(this, 'initialState'),
+        autoInitialState = get(this, 'autoInitialState');
+    if (autoInitialState) {
+      this.initialize();
+    }
+  },
+  initialize: function() {
386 398
     var initialState = get(this, 'initialState');
387 399
388 400
     if (!initialState && getPath(this, 'states.start')) {
9  packages/ember-states/tests/state_manager_test.js
@@ -240,6 +240,15 @@ test("it triggers setup on initialSubstate", function() {
240 240
   ok(grandchildSetup, "sets up grandchild");
241 241
242 242
+test("it does not automatically transition to a default state when autoInitialState is false", function() {
+  stateManager = Ember.StateManager.create({
+    autoInitialState: false,
+    start: Ember.State.create()
+  });
+  equal(get(stateManager, 'currentState'), undefined, "does not transition to initial state");
243 252
 test("it throws an assertion error when the initialState does not exist", function() {
244 253
   raises(function() {
245 254

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.