Search code examples
javascriptember.jsroutesrequirejsamd

Error while processing route: Cannot read property 'connectOutlet' in Ember.js


I'm getting the following error after upgrading Ember to the latest version:

Error while processing route: portfolio Cannot read property 'connectOutlet'

The error takes place whenever I navigate for example from:

http://localhost:8080/#/portfolio

to:

http://localhost:8080/#/publications

The weird thing is that if I refresh the pages many times sometimes it works and some times it's doesn't so feels like some file is loaded too late or maybe loaded twice.

aplication.hbs

The application view renders the header, footer and main container, which contains the application {{outlet}}.

<!-- ... -->
<div class="container" id="maincontainer">
  <div class="maincontainer">
    {{outlet}}
  </div>
</div>
<!-- ... -->

index.hbs

My index view renders a couple of subviews:

<div class="jumbotron fadeInUp animated">
    <div class="row">
        <div id="summary_content">
            {{view view.CvSummaryView}}
        </div>
    </div>
</div>

routes In all my routes I'm only adding the model() function. I'm not overriding renderTemplate() or anything else.

define([
    'Ember'
],
    function (Ember) {
        "use strict";

        return Ember.Route.extend({
            model: function()
            {
                var result = {};

                $.ajax({
                    async: false,
                    dataType: "json",
                    url: './website/js/models/portfolio.json',
                    success: function(data){
                        result.portfolio = data;
                    }
                });

                return result;
            }
        });
    }
);

I tried the following with no luck:

renderTemplate: function(){
    this.render({
        outlet: "main",
        into: "application"
    });
}

Do you have any ideas about what can be the root cause of this issue?

The entire app source code can be found at https://github.com/remojansen/remojansen.github.io/tree/master/website/js

UPDATE 1

I've been reading the Ember documentation and I added {{outlet "main"}} into my application template and tried with:

renderTemplate: function() {
  this.render('blog', {           // the template to render
    into: 'application',          // the template to render into
    outlet: 'main'                // the name of the outlet in that template
  });
}

The I've been debugging the Ember code and I reached this function:

function appendView(route, view, options) {
  if (options.into) {
    var parentView = route.router._lookupActiveView(options.into);
    var teardownOutletView = generateOutletTeardown(parentView, options.outlet);
    if (!route.teardownOutletViews) { route.teardownOutletViews = []; }
    replace(route.teardownOutletViews, 0, 0, [teardownOutletView]);
    parentView.connectOutlet(options.outlet, view);
  } else {
    var rootElement = get(route.router, 'namespace.rootElement');
    // tear down view if one is already rendered
    if (route.teardownTopLevelView) {
      route.teardownTopLevelView();
    }
    route.router._connectActiveView(options.name, view);
    route.teardownTopLevelView = generateTopLevelTeardown(view);
    view.appendTo(rootElement);
  }
}

In the function above, in the line:

var parentView = route.router._lookupActiveView(options.into);

The variable parentView is null and options.into is "application". So the line below throws an exception:

parentView.connectOutlet(options.outlet, view);

I have defined the application template and view but not an application route I don't know if that could be the problem.

Thanks!


Solution

  • After some time debugging I noticed that the ember router._activeViews element didn't always contain the application view:

    Works

    enter image description here

    Doesn't work

    enter image description here

    I tried to analyse why was this happening and because as I said in the question:

    The weird thing is that if I refresh the pages many times sometimes it works and some times it's doesn't so feels like some file is loaded too late or maybe loaded twice.

    I was almost sure that is was related with the usage of require.js and loading application components asynchronously.

    The solution was use deferReadiness() and advanceReadiness(). Here is what I did in case it can help somebody in the future...

    app.js

    define(['Ember'], function (Ember) {
        "use strict";
    
        window.app = Ember.Application.create({
          LOG_TRANSITIONS: false, // basic logging of successful transitions
          LOG_TRANSITIONS_INTERNAL: false, // detailed logging of all routing steps
          LOG_VIEW_LOOKUPS: false // detailed logging of view resolution
        });
    
        // Delay the app's initialization . We will invoke advanceReadiness()
        // when are ready for the app to be initialized
        window.app.deferReadiness();
    
        return window.app;
    });
    

    main.js

    require([
        'website/js/app',
        /* routes, views... */
    ], function (
      app,
      /* routes, views... */
      ){
        "use strict";
    
        // Configure Routes
        app.Router.map(routes);
    
        // Set Routes
        app.IndexRoute = indexRoute;
        // ...
    
        // Set Views
        app.IndexView = indexView;
        // ...
    
        // We're ready to launch the app!
        app.advanceReadiness();
    });