1
votes

I am new to Ember.js. I have two sets of Model/Controller/Templates that handle very similar data and I know they need to be refactored into one. Although the data is very similar, I need it to still be interpreted differently per "Business" or "First" type when output to the template. The templates will split the above types into "Active" or "Inactive" tabs. I'm just not sure what the "correct" ember way would be to do it.

My routes.js

this.resource('manage', function() {
    this.resource('business', function() {
        this.route('active');
        this.route('inactive');
    });
    this.resource('first', function() {
        this.route('active');
        this.route('inactive');
    });

App.FirstRoute = Ember.Route.extend({
    model: function(){
        return App.First.find();
    },
});

App.BusinessRoute = Ember.Route.extend({
    model: function(){
        return App.Business.find();
    },
});

My RESTAdapter (store.js):

App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.reopen({
  buildURL: function(record, suffix) {

      var modelUrlMapping = {}
      modelUrlMapping["first"] = "api/v002/manage.json?me=first"
      modelUrlMapping["business"] = "api/v002/manage.json?me=business"

      var url = ""
      if(modelUrlMapping[record] != undefined ){
        requestUrl = modelUrlMapping[record]
      }
      else{
        requestUrl = this._super(record, suffix);
      }
      return requestUrl;

    }
})

});

Models:

App.First = DS.Model.extend({
    listingId     : DS.attr('string'),
    location    : DS.attr('string'),
    occupied    : DS.attr('string'),
... (define some computed properties specific to First)

App.Business = DS.Model.extend({
    listingId     : DS.attr('string'),
    location    : DS.attr('string'),
    occupied    : DS.attr('string'),
... (define some computed properties specific to Business)

Controllers:

App.ManageController = Ember.ObjectController.extend({
    content: [],
    needs: "application",
    applicationBinding: "controllers.application"
});

App.FirstController = Ember.ArrayController.extend({
    needs: "application",
    applicationBinding: "controllers.application",
    content: [],
    firstInactive: (function() {
    return this.get('content').filterProperty('showLabel') ;
    }).property('[email protected]'),

    firstActive: (function() {
            return this.get('content').filterProperty('showDuration');
    }).property('[email protected]'),
});

App.FirstActiveController = Ember.ArrayController.extend({
    needs: "first",
    firstBinding: "controllers.first",
});


App.FirstInactiveController = Ember.ArrayController.extend({
    needs: "first",
    firstBinding: "controllers.first",
});

App.BusinessController = Ember.ArrayController.extend({
    needs: "application",
    applicationBinding: "controllers.application",
    content: [],
    businessInactive: (function() {
    return this.get('content').filterProperty('showLabel') ;
    }).property('[email protected]'),

    businessActive: (function() {
            return this.get('content').filterProperty('showDuration');
    }).property('[email protected]'),
});

App.BusinessActiveController = Ember.ArrayController.extend({
    needs: "business",
    businessBinding: "controllers.business",
});


App.BusinessInactiveController = Ember.ArrayController.extend({
    needs: "business",
    businessBinding: "controllers.business",
});

Templates ("First " only, "business" are pretty much identical)

first.handlebars (Tab heading):

<div id="content" class="span6">
    <h3 id="page_type" label="first" class="profile_heading">First</h3>
            <ul id="active_inactive_menu" class="nav nav-tabs">
                {{#linkTo 'first.active' tagName='li' href="#"}}<a>Active</a>{{/linkTo}}
                {{#linkTo 'first.inactive' tagName='li' href="#"}}<a>Inactive</a>{{/linkTo}}
            </ul>
        <div class="tab-content">

        {{outlet}}
    </div>          
</div>

first/active.handlebars

<div class="tab-pane active" id="active_list">  
{{#if_not_empty first.firstActive}}
    <ul class="nav nav-tabs nav-stacked">

    {{#each listing in first.firstActive}}
        {{render listingLine listing }}
    {{/each}}   
    </ul>
{{else}}
    No listing found.
{{/if_not_empty}}
</div>

first/inactive.handlebars

<div class="tab-pane" id="inactive_list">
{{#if_not_empty first.firstInactive}}
    <ul class="nav nav-tabs nav-stacked">
    {{#each listing in first.firstInactive}}
        {{render listingLine listing }}
    {{/each}}
    </ul>
{{else}}
    No listing found.
{{/if_not_empty}}
</div>

I've put up a lot of code and I realize these are pretty fundamental Ember.js concepts. But I'm sure there are others with similar questions. What is the correct ember way to re-factor this? Please point out any other gross best practices violations in my examples if you notice them. Thanks!

1

1 Answers

2
votes

Have you tought of reducing repeated code by creating one base controller from which the other controllers can extend from?

This could look something like:

App.BaseController = Ember.ArrayController.extend({
  needs: "application",
  applicationBinding: "controllers.application",
  content: [],
  inactive: (function() {
    return this.get('content').filterProperty('showLabel') ;
  }).property('[email protected]'),

  active: (function() {
    return this.get('content').filterProperty('showDuration');
  }).property('[email protected]'),
});

App.BusinessController = App.BaseController.extend();

App.FirstController = App.BaseController.extend();

As for the models you can do similar things, for example:

App.Base = DS.Model.extend({
  listingId     : DS.attr('string'),
  location    : DS.attr('string'),
  occupied    : DS.attr('string'),
});

App.Business = App.Base.extend();

App.First = App.Base.extend();

And lastly you could also consider using Mixins to share common logic across controllers, models etc.

Hope it helps.