bookthief
bookthief

Reputation: 2451

Accessing computed properties outside of their model in ember.js

I have an ember application with a model called users.js with associated controllers and routing. In my usersController.js, I have a function which counts the number of users in the system. I can then display this figure in my users template. However, I want to display that figure in my index template instead, is this possible? How would I go about it- right now the figure doesn't seem to be available for use outside of my users model.

Here's my usersController-

App.UsersController = Ember.ArrayController.extend({
  sortProperties: ['name'],
  sortAscending: true,

numUsers: function() {
        return this.get('model.length');
    }.property('model.[]')

});

And my html-

  <script type = "text/x-handlebars" id = "index">
  <h2>Homepage</h2>

//This is where I would like the figure to be

  <h3>There are {{numUsers}} users </h3>  
    </script>

<script type = "text/x-handlebars" id = "users">

<div class="col-md-2">
{{#link-to "users.create"}}<button type="button" class="btn btn-default btn-lg"><span class="glyphicon glyphicon-plus"></button> {{/link-to}}

//This works fine

<div>Users: {{numUsers}}</div>
</div>
<div class="col-md-10">

  <ul class="list-group">
  {{#each user in controller}}
  <li class="list-group-item">
    {{#link-to "user" user}}
      {{user.name}}
    {{/link-to}}
  </li>
{{/each}}

</ul>

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

Upvotes: 1

Views: 361

Answers (1)

Marcio Junior
Marcio Junior

Reputation: 19128

You can just load all users in the IndexRoute, something like this:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('user');
  }
});

And extract the shared logic, in that case user count, to a mixin, and use where needed:

App.UsersCountMixin = Ember.Mixin.create({
  numUsers: function() {
    return this.get('model.length');
  }.property('model.[]')
});

App.IndexController = Ember.ArrayController.extend(App.UsersCountMixin, {
});

App.UsersController = Ember.ArrayController.extend(App.UsersCountMixin, {
  sortProperties: ['name'],
  sortAscending: true
});

So {{numUsers}} will be avaliable in your index template.

To share logic with more than one model, you will need to create some alias for model property to avoid ambiguity:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return Ember.RSVP.hash({
      users: this.store.find('user'),
      subjects: this.store.find('subject'),
    })
  }
});

App.UsersCountMixin = Ember.Mixin.create({
  users: Ember.required(),
  numUsers: function() {
    return this.get('users.length');
  }.property('users.[]')
});

App.SubjectsCountMixin = Ember.Mixin.create({
  subjects: Ember.required(),
  numSubjects: function() {
    return this.get('subjects.length');
  }.property('subjects.[]')
});

App.UsersController = Ember.ArrayController.extend(App.UsersCountMixin, {
  users: Ember.computed.alias('model'),
  sortProperties: ['name'],
  sortAscending: true
});

App.SubjectsController = Ember.ArrayController.extend(App.SubjectsCountMixin, {
  subjects: Ember.computed.alias('model'),
  sortProperties: ['name'],
  sortAscending: true
});

App.IndexController = Ember.ArrayController.extend(App.UsersCountMixin, App.SubjectsCountMixin, {});

Of course this is a lot of code to just show the data length, since you can just use:

<h3>There are {{users.length}} users </h3> 
<h3>There are {{subjects.length}} subjecst </h3> 

But I think you will have more complex computed properties to share. In that cases, mixins is a good way to achieve it.

Upvotes: 1

Related Questions