简体   繁体   中英

how to use multiple ember data models in one view

Given these JSON data models on a RESTful server

/users

{"users":[
   {"id":"1","first_name":"John","last_name":"Doe"},
   {"id":"2","first_name":"Donald","last_name":"Duck"}
]}

/users/1

{"user": 
   {"id":"1","first_name":"John","last_name":"Doe","account":"1"}
}

/accounts

{"accounts":[
   {"id":"1","owned_by":"1"},{"id":"2","owned_by":"2"}
]}

/accounts/1

{"account":
   {"id":"1","owned_by":"1","transactions":[1,17]}
}

and these Ember data models

App.Store = DS.Store.extend({
  revision: 11,
  adapter: DS.RESTAdapter.create({
    url: 'http://api.mydomain.ca'
  })
});

App.User = DS.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string'),
    account: DS.belongsTo('App.Account')
});

App.Account = DS.Model.extend({
    ownedBy: DS.belongsTo('App.User'),
    transactions: DS.hasMany('App.Transaction')
});

what other ember code do I have to write to load the data into the models and then write a template that outputs a user's name, account id, and the number of transactions in the account?

I was able to solve this so I will post my code in case it helps someone else. The trick is to make sure the JSON data is formatted exactly how Ember wants it and to create the proper routes.

From what I can tell, Ember expects parent objects to provide a list of child objects. This feels weird to me so if anyone knows a way to do it with child objects referencing their parents with a foreign key please let me know.

I changed the account property on my /user/:user_id JSON object to account_id I also included the account_id on the user objects found at /users and I changed the owned_by property on the account to user_id.

My javascript file

var App = Ember.Application.create();

// Router
App.Router.map(function() {
    this.resource('users', function() {
        this.resource('user', {path:':user_id'});
    }); // '/#/users/:user_id'
    this.resource('accounts', function() {
        this.resource('account', {path:':account_id'});
    });
});

App.IndexRoute = Ember.Route.extend({
    redirect: function() {
        this.transitionTo('users');
    }
});

App.UsersRoute = Ember.Route.extend({
    model: function() {
        return App.User.find();
    }
});

App.AccountsRoute = Ember.Route.extend({
    model: function() {
        return App.Account.find();
    } 
});

// Controllers

App.TransactionsController = Ember.ArrayController.extend();

// Adapter
App.Adapter = DS.RESTAdapter.extend({
    url: 'http://api.mydomain.ca'
});

// Models

App.Store = DS.Store.extend({
  revision: 11,
  adapter: App.Adapter.create({})
});

App.User = DS.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string'),
    account: DS.belongsTo('App.Account')
});

App.Account = DS.Model.extend({
    user: DS.belongsTo('App.User'),
    transactions: DS.hasMany('App.Transaction'),
    balance: function() {
      return this.get('transactions').getEach('amount').reduce(function(accum, item) {
          return accum + item;
      }, 0);
  }.property('transactions.@each.amount')
});

App.Transaction = DS.Model.extend({
    account: DS.belongsTo('App.Account'),
    amount: DS.attr('number'),
    description: DS.attr('string'),
    timestamp: DS.attr('date')
});

And the handlebars templates

<script type="text/x-handlebars" data-template-name="application">
    <div class="row">
        <div class="twelve columns">
            <h2>Accounts</h2>
            <p>{{outlet}}</p>
        </div>
    </div>
</script>

<script type="text/x-handlebars" data-template-name="users">
    <div class="row">
        <div class="three columns" id="users">
            {{#each user in controller }}
                {{#linkTo "user" user class="panel twelve columns"}}{{user.firstName}} {{user.lastName}}{{/linkTo}}
            {{/each}}
        </div>
        <div class="nine columns" id="user">
            {{ outlet }}
        </div>
    </div>  
</script>

<script type="text/x-handlebars" data-template-name="user">
    <h2>{{firstName}} {{lastName}}</h2>
    {{#if account}}
    {{render "account" account}}
    {{else}}
    Error: Account not set up!
    {{/if}}
</script>

<script type="text/x-handlebars" data-template-name="accounts">
    <div class="row">
        <div class="three columns" id="accounts">
            {{#each account in controller }}
                {{#linkTo "account" account class="panel twelve columns"}}{{account.id}} {{account.user.firstName}} {{account.user.lastName}}{{/linkTo}}
            {{/each}}
        </div>
        <div class="nine columns" id="account">
            {{ outlet }}
        </div>
    </div>  
</script>

<script type="text/x-handlebars" data-template-name="account">
    <p>Account Number: {{id}}, Balance: {{balance}}, {{transactions.length}} transactions</p>
    {{render "transactions" transactions}}
</script>

<script type="text/x-handlebars" data-template-name="transactions">
    <table class="table table-striped">
        <thead>
            <tr>
                <th>ID</th>
                <th>Amount</th>
                <th>Timestamp</th>
                <th>Description</th>
            </tr>
        </thead>
        <tbody>
        {{#each transaction in controller}}
            <tr>
                <td>{{transaction.id}}</td>
                <td>{{transaction.amount}}</td>
                <td>{{transaction.timestamp}}</td>
                <td>{{transaction.description}}</td>
            </tr>
        {{/each}}
        </tbody>
    </table>
</script>

Create a Index route that seeds your IndexController with a model and create a related Template that iterates over your relationships.

Here is an example for a simple HasMany-Relationship between post and comments:

var App = Ember.Application.create();
App.Store = DS.Store.extend({
  revision: 11,
  adapter: DS.RESTAdapter.create()
});

App.Post = DS.Model.extend({
  comments: DS.hasMany('App.Comment')
});
App.Comment = DS.Model.extend({
  post: DS.belongsTo('App.Post'),
  body: DS.attr('string'),
});

App.IndexRoute = Ember.Route.extend({
  setupController: function(controller) {
    controller.set('content', App.Post.find("1"));
  }
});

The HTML-Code should look like this:

<!DOCTYPE html>
<html>
<head>
  ...
</head>
<body>
  <script type="text/x-handlebars" data-template-name="index">
  {{#each comment in content.comments}}
    {{comment.body}}
  {{/each}}
  </script>
</body>

And the last but not least the server response /posts/1

{
"post": {
"id": 1,
"title": "Rails is omakase",
"comments": [1, 2, 3]
},

"comments": [{
"id": 1,
"body": "But is it _lightweight_ omakase?"
},
{
"id": 2,
"body": "I for one welcome our new omakase overlords"
},
{
"id": 3,
"body": "Put me on the fast track to a delicious dinner"
}]
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM