4
votes

I have a back-end server(running on node.js) and I am using Ember (v 2.0.2) and Ember-data (2.0.0) with JQuery (2.1.4). The node.js has body-parser and express installed. Front-end libraries are Ember, Ember-data and JQuery

When I fetch data using .findAll() method in the app.ContactsRoute function in the App.js file, I get the following error in the Chrome developer console

Error while processing route: contacts Assertion Failed: You must include an 'id' for undefined in an object passed to 'push' Error: Assertion Failed: You must include an 'id' for undefined in an object passed to 'push' at new Error (native)

There is further to this error with local host website links showing error in the lines of Ember-template-compiler and Ember-data. Just couldn't post it here in the question due to limitation of posting Hyperlinks in the question

Server.js file:

var express = require('express'),
    bodyParser = require('body-parser'),
    app=express();
var id = 7;
var data = {
    1: {id:1, firstName: 'Danny', lastName: 'Stork', email: '[email protected]'},
    2: {id:2, firstName: 'Carlotta', lastName: 'McOwen', email: '[email protected]'},
    3: {id:3, firstName: 'Luther', lastName: 'Ellery', email: '[email protected]'},
    4: {id:4, firstName: 'Finch', lastName: 'Hosky', email: '[email protected]'},
    5: {id:5, firstName: 'Carson', lastName: 'Andrews', email: '[email protected]'},
    6: {id:6, firstName: 'Mac', lastName: 'Parker', email: '[email protected]'},
    7: {id:7, firstName: 'J.D.', lastName: 'Barney', email: '[email protected]'},
};

app.use(bodyParser.json());
app.use(express.static('./public'));

app.route('/api/contacts')
   .get(function(req,res){
      res.json(Object.keys(data).map(function(key){
           return data[key];
       }));
   })
   .post(function(req,res){
       var record = req.body
       record.id = ++id;
   data[record.id] = record;
   res.json(record);
   });

app.route('/api/contacts/:id')
.get(function(req,res){
    res.json(data[req.params.id]);
})
.put(function(req,res){
    data[req.params.id]=req.body;
    res.json(req.body);
})
.delete(function(req,res){
    delete data[req.params.id];
    res.json(null);
});

app.get('*', function(req,res){
    res.sendFile(__dirname + '/public/index.html');
});

app.listen(3000);

app.js file:

var app = Ember.Application.create();

app.ApplicationAdapter = DS.RESTAdapter.extend({
    namespace:'api'
});
app.Contact = DS.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string'),
    email: DS.attr('string')
});

app.ContactSerializer = DS.RESTSerializer.extend({
    extractArray: function(store, primaryType, payload){
        payload ={contacts: payload} ;
        return this._super(store,primaryType,payload);
    },
    extractSingle: function(store, primaryType, payload, recordId){
        payload ={contact: payload} ;
        return this._super(store,primaryType,payload,recordId);
    },
    serializeIntoHash: function(hash,type, snapshot,option){
        var json = this.serialize(snapshot, {included:true});

        Object.keys(json).forEach(function(key){
            hash[key] = json[key];
        });
    }
});

//to get pushstate routes instead of hashbang routes - #!
//access the app.Router class and set the location
app.Router.reopen({
    location: 'history'
});

//routes 
app.Router.map( function(){
    //this.resource used when there is a noun or object behind e.g. /contacts or /contact/:id
    //this.route used when there is no noun or object behind it e.g. /contact/new (no existing data is present)
    this.route('contacts');
    this.route('contact',{path: 'contacts/:contact_id'});
    this.route('new',{path: 'contacts/new'});
});

//this is used for the default route when it doesn't match any other routes in the above list of routes.
app.IndexRoute = Ember.Route.extend({
    redirect: function(){
        this.transitionTo('contacts');
    }
});

app.ContactsRoute = Ember.Route.extend({
    model: function() {
        return this.store.findAll('contact');
    }
})

Index.html:

<html>
    <head>
        <title> Ember Contacts </title>
        <link rel='stylesheet' href='/style.css' />
        <base href="/">
    </head>
    <body>

    <!-- This is like the app class (here id = application is used) defined as top level template -->
    <!-- This is common to all our pages -->
    <script type='text/x-handlebars' id='application'>
        <div id='main'>
            <header>
                <h1> {{#link-to 'contacts'}} Ember Contacts {{/link-to}}</h1>
            </header>
            <div id='app'>
                {{outlet}}
            </div>
        </div>
    </script>
    <script type='text/x-handlebars' id='contacts'>
    <div class='actions'>
     {{#link-to 'new'}} NEW Contact {{/link-to}}
    </div>
    <ul>
        {{#each contact in model}}
            <li>
                {{#link-to 'contact' contact}}
                  {{contact.firstName}} {{contact.lastName}} <span>{{contact.email}}</span>
                {{/link-to}}
            </li>
        {{/each}}
    </ul>
    </script>
    <script src='/lib/jquery/dist/jquery.min.js'></script>
    <script src='/lib/ember/ember-template-compiler.js'></script>       
    <script src='/lib/ember/ember.debug.js'></script>
    <script src='/lib/ember-data/ember-data.js'></script>
    <script src='/app.js'></script>
</body>
</html>

Can someone please help with this issue? Why is this error coming in ember-data?

I am new to ember.js, was completing a tutorial. I could not use the same version that he was using in the video. Hence used the latest version of Ember and Ember-data.

1

1 Answers

1
votes

I have made it work for the latest version. Have changed the following from your code:

In App.js:

Inside app.ContactSerializer = DS.RESTSerializer.extend({ function:

  1. extractArray function has been changed to new function normalizeFindAllResponse (note when changing this function the parameters have changed as well). The function now looks like:

    normalizeFindAllResponse: function(store, primaryModelClass, payload, id, requestType){     
      payload = {contacts: payload};    
      return this._super(store, primaryModelClass, payload, id, requestType); 
    },
    
  2. extractSingle function has been changed to new function normalizeFindRecordResponse (note when changing this function the parameters have changed as well). The function now looks like:

    normalizeFindRecordResponse: function(store, primaryModelClass, payload, id, requestType){  
      payload ={contact: payload} ;     
      return this._super(store, primaryModelClass, payload, id, requestType); 
    },
    

In Index.html, inside the <ul> tag, change "{{#each contact in model}}" to "{{#each model as |contact|}}". And Remove the Handlebars reference <script src='/lib/handlebars/handlebars.js'> </script>. The latest version of Ember doesn't need explicit reference to Handlebars.

Hope this helps, its good to be working with the latest version as the changes are eminent to move forward to newer versions.