4
votes

In the new async router you can async load extra code.

App.ArticlesRoute = Ember.Route.extend({
  beforeModel: function() {
    if (!App.Article) {
      return $.getScript('/articles_code.js');
    }
  }
});

but what if the async code contains extra routes? Ember will have generated them. But I need the ones from the async code, not the ones generated and registered by Ember.

I came up with the following solution (but I'm not pleased with it):

App.ArticlesRoute = Ember.Route.extend({
  beforeModel: function(transition) {
    if (!App.Article) {
      var self = this;
      return $.getScript('/articles_code.js')
        .then(function () {
          return self.reRegisterRoutes(transition, "App", "Article"); //register the routes (with naming convention App.Article__________Route) from the loaded modules (dummies have been generated by Ember) and retry the transaction
        });
    }
  },

  reRegisterRoutes: function (transition, namespaceName, nameStartsWith) { 
    this.container.lookup('route:loading').teardownTopLevelView(); //teardown loading view
    var self = this;
    for (var prop in Ember.Namespace.byName(namespaceName).getOwnProperties()) { //[getOwnProperties](https://gist.github.com/adjohu/1817543)
      if (new RegExp(nameStartsWith + '.+Route', 'i').test(prop)) {
        this.reRegisterRoute(prop.replace(/Route$/, "").camelize()); 
      }
    }
    this.router.router.currentParams = transition.params; //set the parameters of the transition to the currentParams of the router
    return transition.retry(); //retry transaction
  },

  reRegisterRoute: function (routeName) {
    var route = this.container.cache.dict['route:' + routeName];
    if (route != undefined) {
      route.destroy(); //destroy generated route
      delete this.container.cache.dict['route:' + routeName]; //GC
      route = this.container.lookup('route:' + routeName); //register the async loaded route
      route.routeName = routeName; //set the routeName
    }
  }
});

any suggestions?

UPDATE @darshan-sawardekar

I tried your solution end ended up with this:

EEPD.RouteMapper.map(function () {
  this.route('home', { path: '/' });
  this.route('logout');
  this.route('login');

  this.resource('ccpr', function () { //ALL NEEDED FOR THE MENU TO WORK
    this.resource('ccprPatients', { path: '/' }, function () {
        this.route('search');
    });
    this.resource('ccprCardioArticles', { path: "/cardioarticles" });
    this.resource('ccprCardiologists', { path: "/cardiologists" });
    this.resource('ccprInfoSession', { path: "/infosession" }, function () {
        this.route('index');
    });
    this.resource('ccprPatientPresence', { path: "/patientpresence" }, function () {
    });
    this.resource('ccprPresenceOverview', { path: "/presenceoverview" });
    this.resource('ccprNextNutritionalAdvices', { path: "/nextnutritionaladvices" });
    this.resource('ccprParameter', { path: "/parameter" });
    this.resource('ccprListStaff', { path: "/liststaff" });
  });
});

then in the seperated loaded file

EEPD.RouteMapper.map(function () {
  this.resource('ccpr', function () {
    this.resource('ccprPatients', { path: '/' }, function () {
        this.route('search');
    });
    this.resource('ccprPatient', { path: '/:ccpr_patient_id' }, function () {
        this.resource('ccprPracticeSessions', { path: '/practicesessions' }, function () {
        });
        this.resource('ccprPracticeSession', { path: '/practicesessions/:ccpr_practiceSession_id' }, function () {
            this.route('info');
            this.route('anamnese');
            this.route('medication');
            this.route('trainingModel', { path: '/trainingmodel' });
            this.route('socialEvaluation', { path: '/socialevaluation' });
            this.route('medicalFollowUp', { path: '/medicalfollowup' });
            this.resource('ccprPracticeSessionPsychologicalEvaluation', { path: '/psychologicalevaluation' }, function () {
                this.resource('ccprPracticeSessionPsychologicalEvaluationMnhds', { path: '/mnhd' });
                this.resource('ccprPracticeSessionPsychologicalEvaluationMnhd', { path: '/mnhd/:ebed_questionaire_id' });
                this.resource('ccprPracticeSessionPsychologicalEvaluationHadss', { path: '/hads' });
                this.resource('ccprPracticeSessionPsychologicalEvaluationHads', { path: '/hads/:ebed_questionaire_id' });
                this.resource('ccprPracticeSessionPsychologicalEvaluationDs14s', { path: '/ds14' });
                this.resource('ccprPracticeSessionPsychologicalEvaluationDs14', { path: '/ds14/:ebed_questionaire_id' });
            });
            this.resource('ccprPracticeSessionNutritionalAdvice', { path: '/nutritionaladvice' }, function () {
                this.resource('ccprPracticeSessionNutritionalAdviceBmi', { path: '/bmi/:ebed_nutritionBmi_id' });
                this.resource('ccprPracticeSessionNutritionalAdviceDietContact', { path: '/dietcontact/:ebed_dietContact_id' });
            });
            this.route('decision', { path: '/decision' });
            this.resource('ccprPracticeSessionApprovals', { path: '/approvals' }, function () {
                this.resource('ccprPracticeSessionApproval', { path: '/:erevalidatie_approval_id' });
            });
        });
    });
    this.resource('ccprCardioArticles', { path: "/cardioarticles" });
    this.resource('ccprCardiologists', { path: "/cardiologists" });
    this.resource('ccprInfoSession', { path: "/infosession" }, function () {
        this.route('addPatient');
    });
    this.resource('ccprPatientPresence', { path: "/patientpresence" }, function () {
        this.route('index');
        this.route('addPatient');
    });
    this.resource('ccprPresenceOverview', { path: "/presenceoverview" });
    this.resource('ccprNextNutritionalAdvices', { path: "/nextnutritionaladvices" });
    this.resource('ccprParameter', { path: "/parameter" });
    this.resource('ccprListStaff', { path: "/liststaff" });
  });
}, true);

It doesn't work, only if I combine it with my solution, it works partialy. I got errors like Assertion failed: The route ccprPracticeSession.info was not found and Uncaught Error: There is no route named ccprPracticeSession.info.index

1

1 Answers

1
votes

You could store all the route maps into another object, and then call Router.map, iterating through the maps. Something like,

App.RouteMapper = Ember.Object.extend({
});

App.RouteMapper.reopenClass({
  maps: null,

  map: function(callback, reassign) {
    if (!this.maps) this.maps = new Array();

    this.maps.push(callback);
    if (reassign) {
      this.assign();
    }
  },

  assign: function() {
    var self = this;
    App.Router.map(function() {
      var routerScope = this;
      self.maps.forEach(function(map) {
        map.call(routerScope);
      });
    });
  }
});

App.RouteMapper.map(function() {
  this.route('lorem');
  this.route('ipsum');
});

The sub module loaded code calls App.RouteMapper.map that would rebuild the entire set of routes from the maps stored. The maps are the same callbacks as you would pass to Router.map so that api wouldn't change.