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: 'dannystork#example.com'},
2: {id:2, firstName: 'Carlotta', lastName: 'McOwen', email: 'carlottamcowen#example.com'},
3: {id:3, firstName: 'Luther', lastName: 'Ellery', email: 'lutherellery#example.com'},
4: {id:4, firstName: 'Finch', lastName: 'Hosky', email: 'finchhosky#example.com'},
5: {id:5, firstName: 'Carson', lastName: 'Andrews', email: 'carsonandrews#example.com'},
6: {id:6, firstName: 'Mac', lastName: 'Parker', email: 'macparker#example.com'},
7: {id:7, firstName: 'J.D.', lastName: 'Barney', email: 'jdbarney#example.com'},
};
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.
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:
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);
},
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.
Related
I'm trying to implement pagination in keystone js andf I'm doing it as follows:
Model
var keystone = require('keystone');
var Types = keystone.Field.Types;
var Test = new keystone.List('Test', {
map: {name: 'title'},
label: 'Test',
singular: 'Test',
plural: 'Tests',
autokey: {path: 'slug', from: 'title', unique: true}
});
Test.add({
description: {type: Types.Html, wysiwyg: true, height: 300 }
});
Test.register();
Route / View
var keystone = require('keystone');
var Test = keystone.list('Test');
exports = module.exports = function(req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
// Set locals
locals.section = 'test';
locals.data = {
test: []
};
Test.paginate({
page: req.query.page || 1,
perPage: 2,
maxPages: 5
})
.exec(function(err, results) {
locals.data.test = results;
next(err);
});
// Load All Terms
view.query('test', keystone.list('Test').model.find());
// Render view
view.render('test');
}
In Index.js
app.all('/test', routes.views.test);
In middleware.js
res.locals.navLinksFooter = [
{ label: 'Test', key: 'test', href: '/test' },
.....
];
Template
<div class="row">
<div class="col-xs-12">
<span class="pull-right">
{{>pagination}}
</span>
</div>
</div>
<div class="row row-content panel--outer panel--outer--trans">
<div class="col-xs-12" id="panel--news-detail">
{{# each test}}
<p>{{{description}}}</p>
{{/each}}
</div>
</div>
Unfortunately, when I try to go to the page I get the following error:
"ReferenceError: next is not defined"
Some pointers and possible causes. I've already set up pagination for blog posts on a separate page using:
locals.data = {
test: []
};
If I comment out "next(err)", the pagination buttons appear but clickiong on the arrow takes me to the second page of blog/news items.
Things are obviously getting mixed up somewhere here. I suspect it's due to my mishandling of locals but I can't seem to find any in depth explanation on the keystone site of how locals are supposed to work.
I ultimately want to apply different filters to the mongo collection and have it running in a series of bootstrap tabs but I think I need to get the basics sorted out first.
Has anyone been faced with a similar situation and been able to find the solution?
next is a callback function that runs within your Express route. You don't have it defined as an argument in your route at all; part of the problem is also that you are trying to load the data synchronously, which doesn't work here.
Use the view.init function to expose the next function, then call it when you've loaded information from your database into locals.data.
route/view
var keystone = require('keystone');
var Test = keystone.list('Test');
exports = module.exports = function(req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
// Set locals
locals.section = 'test';
locals.data = {
test: []
};
view.on('init', function (next) {
Test.paginate({
page: req.query.page || 1,
perPage: 2,
maxPages: 5
})
.exec(function(err, results) {
locals.data.test = results;
next(err);
});
});
// Load All Terms
view.query('test', keystone.list('Test').model.find());
// Render view
view.render('test');
}
So I have already made a Restful API with node and everything works but I am trying to add EJS to it so I can use HTML&CSS, I implemented GET and POST just fine but I am tripping up on DELETE.
Here is my code in my router to delete
listRouter.delete('/:id',
function(req, res) {
req.list = list;
req.list.remove(function(err){
if (err)
res.status(500).send(err);
else
res.redirect('/')
});
});
and here's my EJS for deletion
<form method="DELETE" action="/:id">
<button type="submit">Delete</button>
</form>
and this is the error I receive when I press the button
{
message: "Cast to ObjectId failed for value ":id" at path "_id"",
name: "CastError",
kind: "ObjectId",
value: ":id",
path: "_id"
}
The thing is though the same exact code works if it's modified for JSON so I don't know if its EJS or my Javascript.
Thanks
i think html5 just support post and get in method form attribute
however, in my case if i don't using form for submit, here example
example in html or front end
<a class="btn btn-raised btn-danger" href="/admin/dashboard/detele/<%= data.userId %>">Delete</a></td>
<!-- The href needs to point at a link where data.userId is shown. Hence you need the = after <% for ejs to show the variable. -->
In app.js for the url delete
app.get('/admin/dashboard/detele/:id', users.deleteUser);
in express users.js
exports.deleteUser = function(req, res) {
users.findOneAndRemove({
userId: req.params.id
}, function(err, user) {
if (err) throw err;
console.log("Success");
});
res.redirect('/admin/dashboard');
}
don't forget creating mongo model for mongoose
var skema = new mongo.Schema({
name: String,
email: String,
password: String,
date: {
type: Date,
default: Date.now
},
admin: Boolean
});
var users = mongo.model('accounts', skema);
i using EJS here, hope it's help you
more helpful link1
more helpful link2
giving up use of method-override can be solution
I used different url to solve this.
<form action="/quake/forum/update/<%= post._id %>?_method=put" method="post">
and
<form action="/quake/forum/delete/<%= post._id %>?_method=delete" method="post" class="d-inline">
and router
main router
app.use('/quake/forum',forumRouter); //this is for just making sure explaination clear
sub router (forumRouter)
router.post('/delete/:id', function (req, res) {
and
router.post('/update/:id', function (req, res) {
I'm pretty new to Ember.js and am building an app to pick up some Ember chops. I wanted to use a computed property in one of my models as a route but it seems something isn't working correctly. I'm using FIXTURES by the way.
What I'm trying to achieve is /peeps/john-smith instead of /peeps/1
I've got my model setup like this:
App.Peep = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
slug: function(){
this.get('firstName').toLowerCase() + '-' + this.get('lastName').toLowerCase();
}.property('firstName', 'lastName')
});
My router setup is like this:
App.Router.map(function(){
this.resource('peep', { path: '/peeps/:peep_slug'});
});
App.PeepRoute = Ember.Route.extend({
model: function(params){
return this.store.find('peep', params.peep_slug);
},
serialize: function(model){
return { peep_slug: model.get('slug') };
}
});
When I navigate to /peeps/john-smith in the browser, I get this warning in my console You made a request for a peep with id john-smith.
Is there something I'm missing?
By default it searches by id param, so you could either change the adapter to make it search by slug or try to add id as Ember.computed.alias('slug').
I've set up an ember.js client with ember-data as persistance handler.
Fetching all records from the DB works fine with this code:
router.js
App.ProjectsRoute = Ember.Route.extend({
model: function() {
return this.store.find('project');
}
});
But adding a new record doesn't work correctly with this code. It's only added to the model and not persisted.
index.html (example)
{{input type="text" id="newTitle" value=Title}}
<button class="small" {{action 'createProject'}}><i class="icon-plus-sign"></i></button>
Controller.js
App.ProjectsController = Ember.ArrayController.extend({
actions: {
createProject: function () {
var project = this.store.createRecord('project', {
project_number: this.get('newProject_number'),
title: this.get('newTitle'),
client: this.get('newClient'),
comment: this.get('newComment'),
xmlfile: this.get('newXmlfile')
});
this.set('newProject_number', '');
this.set('newTitle', '');
this.set('newClient', '');
this.set('newComment', '');
project.save();
}
}
});
models.js
App.Project = DS.Model.extend({
title: DS.attr('string'),
client: DS.attr('string'),
comment: DS.attr('string'),
project_number: DS.attr('string'),
});
app.js
window.App = Ember.Application.create();
App.store = DS.Store.extend({
adapter: DS.RESTAdapter,
});
DS.RESTAdapter.reopen({
namespace: 'api/index.php',
headers: {
"API_KEY": "secret key",
"ANOTHER_HEADER": "Some header value"
}
});
Framework versions
Ember : 1.2.0;
Ember Data : 1.0.0-beta.5+canary.e120006;
Handlebars : 1.1.2;
jQuery : 2.0.3;
What have I missed to configure? There's no error in the console however.
REST-Api works well with curl.
The problem is the structure of the JSON "POST"ed towards the API:
Sent:
{project: {client: "test",comment: "test",project_number: "test",title: "test"}}
Expected by API-Backend:
{client: "test",comment: "test",project_number: "test",title: "test"}
I wonder where I could have found the information how ember-data build it's requests. (For further development)
I have a basic router for posts index and show action. If I navigate to a single post, it renders the page correctly and sets the URL to /#/posts/foo. But if I copy the URL and paste it into a new tab, it will load the page, but the url will change to /#/posts/null. Other than that the page is rendered properly and no errors are shown
show: Em.Route.extend({
route: "/post/:id",
serialize: function(router, context) {
return { id: context.get("id") };
},
deserialize: function(router, context) {
return App.get("store").find(App.Post, context.id);
},
connectOutlets: function(router, context) {
router.get("applicationController").connectOutlet("body", "post", context);
}
})
with a simple model
App.Post = DS.Model.extend({
id: DS.attr("string"),
title: DS.attr("string"),
content: DS.attr("string"),
image: DS.attr("string")
});
and the log looks like this
STATEMANAGER: Entering root ember.js:17420
STATEMANAGER: Sending event 'navigateAway' to state root. ember.js:17172
STATEMANAGER: Sending event 'unroutePath' to state root. ember.js:17172
STATEMANAGER: Sending event 'routePath' to state root. ember.js:17172
STATEMANAGER: Entering root.show
and a router
App.Store = DS.Store.extend({
revision: 4,
adapter: DS.RESTAdapter.create({
bulkCommit: false
})
});
Your route should be '/post/:post_id' instead of 'post/:id'. The parameter name is composed of the decapitalized model name, an underscore and the attribute name.
Doing this way you don't need serialize/deserialize method, Ember.js will do the job for you
The issue was specifying id as an attrirbute. You should never do that and let Ember Data take care of it automatically.
App.Post = DS.Model.extend({
title: DS.attr("string"),
content: DS.attr("string"),
image: DS.attr("string")
});