0
votes

I have to replicate the same behaviour (nested routes, models, controller functions, store functionality) for like 12 different routes. The only difference is in their model attributes for which the template will also be updated. So for instance I have two routes named Notes and Tasks which are fetched in the same way and also have the same functionality in the controller but the Tasks route has attributes say Subject and Text whereas Notes has Name and Description but even the template functionality is the same.

What would be the best approach to not repeat the same functionality for such routes? Can one model or route or controller be created generic enough such that ember.js can decide on run time to do stuff for each individual route? Can I reuse one model/controller/route's functionality for the 12 different routes that I have?

1

1 Answers

2
votes

Note: Idiomatic Ember 2.x favors using components over controllers, but I've answered using controllers because the question specified controller.

You can make use of inheritance by defining a base route that contains your common functionality and uses properties that will be defined by the child classes in order to customize the behavior.

// routes/base.js
import Ember from 'ember';

export default Ember.Route.extend({
  // shared route definition
  modelName: null,
  attributes: [],
});

// routes/note.js
import BaseRoute from 'base';

export default BaseRoute.extend({
   modelName: 'note',
   attributes: ['name', 'description'],
});

// routes/task.js
import BaseRoute from 'base';

export default BaseRoute.extend({
    modelName: 'task',
    attributes: ['subject', 'text'],
});

You can do the same thing for controllers. There is no template inheritance, but you can either use partials or override the templateName attribute in the route.

Partials:

<!-- template/base.hbs -->
<p>Template Markup for {{modelName}}</p>

// controllers/note.js
import BaseController from 'base';

export default BaseController.extend({
   modelName: 'note',
});

<!-- template/note.hbs -->
{{partial 'base'}}

Overriding templateName:

<!-- templates/base.hbs -->
<p>Base Template Markup</p>

// routes/note.js
export default BaseRoute.extend({
   modelName: 'note',
   attributes: ['name', 'description'],
   templateName: 'base',
});

With inheritance, it's simplest if your attributes actually share a property name and only differ in their display name (e.g. the attribute for name/subject is title and the attribute for text/description is text while retaining the display names Name/Subject and Text/Description respectively). If this isn't the case, you are going to need a way to refer to the properties you want to reference in the template (e.g. whether to use model.name or model.subject) and that will get pretty messy. It's much easier to define displayForText:

<!-- template/base.hbs -->
<p>{{displayForTitle}}: {{model.title}}</p>
<p>{{displayForText}}: {{model.text}}</p>

// controllers/note.js
import BaseController from 'base';

export default BaseController.extend({
   displayForTitle: 'Name',
   displayForText: 'Description',
});