Search code examples
javascriptember.jsember-model

Ember-Model EmbeddedHasManyArray not updating in template's each helper


I am using ember-model for a simple invoicing app, i am new to ember and i cannot fix what's happening here, basically i am using ember-model's hasMany for embedded nested data, (the items for each invoice are in an array), i tried putting the code on jsbin and jsfiddle but it doesn't work up there, so for those who have time to help i put up an archive on my dropbox here : Ember-Model hasMany not updating in template's {{#each}}

To reproduce the bug, navigate to an invoice, then navigate to another invoice using the links, watch the items not updating as if they were stuck, but if you reload the page you will get the right items, what am i doing wrong :/ ?

The following code is of course a very simplified version of my actual app but it does reproduce the bug..

Thanks to anyone willing to help.

Index.html

<!DOCTYPE html>
<html>
<head>
  <meta name="description" content="Ember - Starter" />
  <meta charset=utf-8 />
  <title>Ember-Model</title>
  <script src="libs/jquery-1.9.1.js"></script>
  <script src="libs/handlebars-1.0.0.js"></script>
  <script src="libs/ember-1.1.2.js"></script>
  <script src="libs/ember-model-latest.js"></script>
  <script src="app.js"></script>
</head>
<body>

<script type="text/x-handlebars">
  <h1>Invoices</h1>
  {{ outlet }}
</script>

<script type="text/x-handlebars" data-template-name="factures">
{{#each}}
    <ul>
        <li>{{#link-to 'facture' this}}{{title}}{{/link-to}}</li>
    </ul>
{{/each}}
  <hr/>
    {{outlet}}
</script>

<script type="text/x-handlebars" data-template-name="facture">
<h2>Items for {{title}}</h2>
{{#each items}}
<ul>
  <li>{{desc}}</li>
</ul>
{{/each}}
</script>

</body>
</html>

App.js

var App = Ember.Application.create();

// ROUTER
App.Router.map(function () {
    this.resource('factures', function () {
        this.resource('facture', {
            path: '/:facture_id'
        });
    });
});

App.FacturesRoute = Ember.Route.extend({
    model: function (params) {
        return App.Facture.find();
    }
});

App.FactureRoute = Ember.Route.extend({
    model: function (params) {
        return App.Facture.fetch(params.facture_id).then(function (modelData) {
            return App.Facture.find(params.facture_id);
        });
    }
});

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


// MODELS
var attr = Ember.attr,
    hasMany = Ember.hasMany,
    belongsTo = Ember.belongsTo;

// Factures
App.Facture = Ember.Model.extend({
    title: attr(),
    items: hasMany('App.Item', {
        key: 'items',
        embedded: true
    })
});

App.Facture.adapter = Ember.FixtureAdapter.create();

// Facture
// -> [ Items ]
App.Item = Ember.Model.extend({
    desc: attr(""),
    qty: attr("number"),
    price: attr("string")
});

// FIXTURES

App.Facture.FIXTURES = [
{
    id: 1,
    title: "Invoice #1",
    items: [
        {id: 1, desc: 'An Item for #1', qty: 2, price: "45"}, 
        {id: 2, desc: 'An Item for #1', qty: 5, price: "75"}
    ]
}, 
{
    id: 2,
    title: "Invoice #2",
    items: [
        {id: 1, desc: 'An Item for #2', qty: 2, price: "250"},
        {id: 2, desc: 'An Item for #2', qty: 5, price: "200"}
    ]
}];

Solution

  • Your items id's should be unique, ember model doesn't care if it's embedded or not, if it sees the same id it returns the model that's already existing for that id.

    http://emberjs.jsbin.com/eKibapI/1/edit

    App.Facture.FIXTURES = [
    {
        id: 1,
        title: "Invoice #1",
        items: [
            {id: 1, desc: 'An Item for #1', qty: 2, price: "45"}, 
            {id: 2, desc: 'An Item for #1', qty: 5, price: "75"}
        ]
    }, 
    {
        id: 2,
        title: "Invoice #2",
        items: [
            {id: 3, desc: 'An Item for #2', qty: 2, price: "250"},
            {id: 4, desc: 'An Item for #2', qty: 5, price: "200"}
        ]
    }];