My model:
var Backbone = require('backbone');
module.exports = Backbone.Model.extend({
idAttribute: '_id',
defaults: {
id: 0,
description: '',
amount: 0,
dateEntry: new Date(),
positive: false
},
url: '/api/transactions'
});
My collection:
var Backbone = require('backbone');
var Transaction = require('../models/Transaction')
var TransactionCollection = Backbone.Collection.extend({
model: Transaction,
url: '/api/transactions',
initialize: function() {
this.hasNextPage = false;
this.filter = 'all';
},
parse: function(response) {
this.hasNextPage = response.hasNextPage;
this.balance = response.balance;
return response.transactions || [];
}
});
module.exports = new TransactionCollection();
I have a number of item views, each displaying its model data (transaction).
In each item view there's a "delete" button which triggers:
delete: function() {
console.log("Remove:: ");
console.log(this.model.toJSON());
this.model.destroy();
}
Looking at the console, I see the REST DELETE call to /api/transactions/
Shouldn't it be /api/transaction/model_id ? Actually, I see empty req.body and req.query on the server side (NodeJS).
The browser console logs:
[Log] Object (app.js, line 20298)
__v: 0
_id: "5421da84c6fd7c91060ba405"
amount: 1200
category: Object
dateAdded: "2014-09-23T20:39:32.905Z"
dateEntry: "2014-06-17T22:00:00.000Z"
description: "Example!"
id: 0
positive: true
user: "53fbb34fb91a922f03be61f8"
__proto__: Object
Transaction data is coming from MongoDB, thus having the _id property.
I suspect that is the reason of my problem. How can I have my Backbone app calling the right DELETE url?
In your model you're overriding the url property when you should be overriding the urlRoot property
//intercept the request for testing.
$.mockjax({
// matches /api/transactions/abCD1234
url: /^\/api\/transactions\/([0-9a-zA-A]+)$/,
urlParams: ['id'],
response: function (settings) {
var id = settings.urlParams.id;
$('body').append(id);
}
});
var yourModel = Backbone.Model.extend({
idAttribute: '_id',
defaults: {
id: 0,
description: '',
amount: 0,
dateEntry: new Date(),
positive: false
},
//This is the property that sets the "base" of all your REST urls
urlRoot: '/api/transactions'
});
var yourInstance = new yourModel({
_id:'5421da84c6fd7c91060ba405',
amount: 1200,
dateAdded: "2014-09-23T20:39:32.905Z",
dateEntry: "2014-06-17T22:00:00.000Z",
description: "Example!",
id: 0,
positive: true,
user: "53fbb34fb91a922f03be61f8"
});
yourInstance.destroy();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-mockjax/1.5.3/jquery.mockjax.min.js"></script>
Related
I have the following schema:
var Person = new Schema({
persondetails: {
name: {
type: String,
uppercase: true,
required: true
},
nationalities: [ {
nationality : String
}]
});
and a presave function to check modified paths:
schema
.pre('save', function(next) {
var document = this;
_.each(document.modifiedPaths(), function(path) {
console.log(path);
});
return next();
});
if i do:
new Person({persondetails: {
name: 'Some Name',
nationalities: [ {nationality: 'Some Country'}]
}
)
Or even pick an already existing 'Person' and add a new element to its nationalities array,
presaved hook prints:
persondetails
persondetails.name
persondetails.nationalities
But i was expecting the 'persondetails.nationalities.0.nationality' as well.
Is this expected behavior or am i missing something ?
I have a mongoose model containing 2 properties Array of String and some others:
var Model = new Schema({
_id: {type: Number, required: true, unique: true},
name: {type: String, required: true},
oneList: [String],
anotherList: [String]
});
I create the model:
var model = new Model({
_id: 1,
name: 'model',
oneList: ['a', 'b'],
anotherList: ['c', 'd']
})
but when I inspect the model all the list are undefined:
model._doc === {
_id: 1,
name: 'model',
oneList: undefined,
anotherList: undefined
}
I tried some variations:
change the model definition from [String] to [ ]
create separately the data outside the model then pass it
create the model without list data then add it to the model
Even when I create an empty model:
var model = new Model({})
model._doc.oneList === undefined
model._doc.anotherList === undefined
Context:
The problem occurs on a docker container but not on my local machine
node: v4.4.7
mongoose: v4.6.0
GitHub
I had the same issue, apparently when you have a nested array within your model, mongoose has an open issue 1335 that saves an empty array when a property references a schema. I experimented with presaves to force the property to be an empty array if the property's length is 0 or undefined.
Also be careful when specifying unique=true in the property's schema, as empty or undefined properties will violate the indexing and throw an error.
Note:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var barSchema = new mongoose.Schema({
baz: String
});
var fooSchema = new mongoose.Schema({
bars: [barSchema]
});
var Foo = mongoose.model('Foo', fooSchema);
var foo = new Foo();
console.log(foo); // { _id: 55256e20e3c38434687034fb, bars: [] }
foo.save(function(err, foo2) {
console.log(foo2); // { __v: 0, _id: 55256e20e3c38434687034fb, bars: [] }
foo2.bars = undefined;
foo2.save(function(err, foo3) {
console.log(foo3); // { __v: 0, _id: 55256e20e3c38434687034fb, bars: undefined }
Foo.findOne({ _id: foo3._id }, function(err, foo4) {
console.log(foo4); // { _id: 55256e20e3c38434687034fb, __v: 0, bars: [] }
mongoose.disconnect();
});
});
});
You can do like this:
var schema = new Schema({
_id: {
type: Number,
required: true,
unique: true
},
name: {
type: String,
required: true
},
oneList: [String],
anotherList: [String]
}),
Model = mongoose.model('Model', schema),
m = new Model();
m._id = 1;
m.name = 'model';
m.oneList.push('a', 'b');
m.anotherList.push('c', 'd');
I´m new to Backbone.js, but after some research I still couldn´t find the source of my problem.
I am developing an App and I have a collection of models, which I eventually want to display in a view (just one model at a time).
Here´s my code so far:
var App = {
Item: Backbone.Model.extend({
defaults: function() {
return {
id: -1,
name: '',
imageReference: '',
itemTags: []
};
},
sync: function() { return null; },
fetch: function() { return null; },
save: function() { return null; }
}),
Items: Backbone.Collection.extend({
model: this.Item,
}),
ItemView: Backbone.View.extend({
el: "#itemdiv",
tagName: "<div>",
className: "item",
template: _.template($("#template-item-view").html()),
initialize: function(model) {
this.model = model;
this.listenTo(this.model, "change", this.render);
this.render();
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
})
};
var items = new App.Items();
items.add(new App.Item({name: "iPhone", id: 1, imageReference: "iPhone.jpg", ["mobile", "smartphone"]}));
items.add(new App.Item({name: "MacBook", id: 2, imageReference: "MacBook.jpg", ["laptop", "computer"]}));
All of the above works. When I inspect items it has the two models including the parameters. But when I try to add a new item directly to the Collection with Collection.create() like:
items.create({name: "Apple Watch", id: 3, imageReference: "AppleWatch.jpg", ["watch", "redundant"]});
it throws an error:
TypeError: undefined is not a constructor (evaluating 'new this.model(attrs, options)')
In case it helps, this error appears in Backbone.js in line 915 (dev version), the wrapping function is
/* from Backbone.js, Dev-Version, Line 911-919 */
_prepareModel: function(attrs, options) {
if (attrs instanceof Model) return attrs;
options = options ? _.clone(options) : {};
options.collection = this;
var model = new this.model(attrs, options);
if (!model.validationError) return model;
this.trigger('invalid', this, model.validationError, options);
return false;
}
I can´t figure out if that is just a small bug or if something with my architecture is wrong. Am very thankful for help and also on comments towards best practices, etc.
Thanks in advance!
You have an error in your add lines:
items.add(new App.Item({name: "iPhone", id: 1, imageReference: "iPhone.jpg", ["mobile", "smartphone"]}));
items.add(new App.Item({name: "MacBook", id: 2, imageReference: "MacBook.jpg", ["laptop", "computer"]}));
Should be:
items.add(new App.Item({name: "iPhone", id: 1, imageReference: "iPhone.jpg", itemTags: ["mobile", "smartphone"]}));
items.add(new App.Item({name: "MacBook", id: 2, imageReference: "MacBook.jpg", itemTags: ["laptop", "computer"]}));
The field itemTags was missing. Does that fix it?
The point at which the following is run:
Items: Backbone.Collection.extend({
model: this.Item,
}),
this isn't known.
So if you're namespacing to encapsulate your code do one of either:
var App = {}
App.item = Backbone.Model.extend({...})
App.items = Backbone.Collection.extend({...})
App.itemView = Backbone.View.extend({...})
App.items.add({})
App.items.add({})
Or:
(function() {
var item = Backbone.Model.extend({...})
var items = Backbone.Collection.extend({...})
var itemView = Backbone.View.extend({...})
var items.add({})
var items.add({})
})()
I use Backbone-Relational to create a complex hierarchy of models, the code looks like this:
var ModelA = Backbone.Model.extend({
initialize: function () {
console.log('model a initialized!')
}
});
var CollectionA = Backbone.Collection.extend({
model: ModelA
});
var ModelB = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'Collection',
collectionType: CollectionA
}]
});
var data = new ModelB({
name: 'ModelB',
Collection: [{
name: 'ModelA-1'
}, {
name: 'ModelA-2'
}]
});
console.log(data.get('Collection').at(0) instanceof ModelA); // false
console.log(data.get('Collection').at(0) instanceof ModelB); // true
console.log(JSON.stringify(data.toJSON()));
// {"name":"ModelB","Collection":[{"name":"ModelA-1","Collection":[]},{"name":"ModelA-2","Collection":[]}]}
As you see, even though ModelB is successfully created, initialize() of ModelA isn't called. Checking the types proves that the objects inside the collection are not ModelA. How can I fix this?
Two changes necessary: make ModelA a RelationalModel (and not just a standard one), and tell ModelB that ModelA is its relatedModel, like this:
var ModelA = Backbone.RelationalModel.extend({
initialize: function () {
console.log('model a initialized!')
}
});
...
var ModelB = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
relatedModel: 'ModelA',
key: 'Collection',
collectionType: CollectionA
}]
});
Demo.
First time of trying to post data from backbone to REST using model collection of backbone.
define(["underscore" , "backbone"],function(_ , Backbone){
var CustomerModel = Backbone.Model.extend({
urlRoot: 'http://myresturl/api/CusWeb',
initialize: function(){
},
defaults : {
UID: "00000000-0000-0000-0000-000000000000",
Sex: 0,
Name: "",
Company: "",
Address: "",
Email: ""
}
});
return CustomerModel;
});
define(["underscore","backbone","models/CustomerModel"] , function(_ ,Backbone,CustomerModel){
var CustomerCollection = Backbone.Collection.extend({
url: 'http://myresturl/api/CusWeb',
model:CustomerModel
});
return CustomerCollection;
});
I'm trying to post data from backbone to REST URL by clicking on a button in backbone view.
define(["jquery" ,
"underscore" ,
"backbone" ,
"text!templates/Customer/registerCustomerTemplate.html",
"models/CustomerModel",
"user",
],function($ , _ , Backbone, RegisterDescriptionTem, CustomerModel, Customer){
var userObj = new Customer();
var ContainerRegisterView = Backbone.View.extend({
el : $("#webbodycontainer"),
initialize : function(){
},
events : {
'click #register' : 'registerUser'
},
registerUser : function(){
this.model.set({
UID: "00000000-0000-0000-0000-000000000000",
Sex: 1,
Name: "",
Company: "",
Address: "",
Email: ""
});
this.model.save();
console.log(this.model.get('Sex'));
},
render : function(){
var _registerDes = _.template(RegisterDescriptionTem);
this.model = new CustomerModel();
this.$el.append(_registerDes((this.model.toJSON())));
}
});
return ContainerRegisterView;
});
console.log(this.model.get('Sex')); is shown in browser's console (1) but data didn't save to database.
Here is the router :
define([
.....
'views/Customer/ContainerRegister',
], function(ContainerRegister){
var AppRouter = Backbone.Router.extend({
routes: {
......
}
var app_router = new AppRouter;
app_router.on('route:registerAction', function(register){
if(window.currentSection){
window.currentSection.remove();
}
window.currentSection = new ContainerRegister({});
$('#webbodycontainer').html(window.currentSection.$el);
window.currentSection.render(register);
});
});
I appreciate any other information that you can provide. Thanks.
Check initializing your model. and also while saving try to give first parameter as null.
define(["jquery" ,
"underscore" ,
"backbone" ,
"text!templates/Customer/registerCustomerTemplate.html",
"models/CustomerModel",
"user",
],function($ , _ , Backbone, RegisterDescriptionTem, CustomerModel, Customer){
var ContainerRegisterView = Backbone.View.extend({
el : $("#webbodycontainer"),
//check initializing your model here.
initialize : function(){
_.bindAll(this);
this.model = new Customer();
},
events : {
'click #register' : 'registerUser'
},
registerUser : function(){
this.model.set({
UID: "00000000-0000-0000-0000-000000000000",
Sex: 1,
Name: "",
Company: "",
Address: "",
Email: ""
});
this.model.save(null,{
success:function(){
//code after success
},error:function(){
//code after error
},
});
console.log(this.model.get('Sex'));
},
render : function(){
var _registerDes = _.template(RegisterDescriptionTem);
this.model = new CustomerModel();
this.$el.append(_registerDes((this.model.toJSON())));
}
});
return ContainerRegisterView;
});
I think your issue might be lack of a model id. For backbone<->server interactions, you might find that the id property is required. Try modifying your code as follows:
define(["underscore" , "backbone"],function(_ , Backbone){
var CustomerModel = Backbone.Model.extend({
urlRoot: 'http://myresturl/api/CusWeb',
initialize: function(){
},
defaults : {
UID: "00000000-0000-0000-0000-000000000000",
Sex: 0,
Name: "",
Company: "",
Address: "",
Email: ""
},
idAttribute: "UID" // set "UID" as the alias for "id"
});
return CustomerModel;
});
Here's a blog post on a similar issue that goes into a little more detail http://blog.markstarkman.com/blog/2012/02/13/getting-backbone-dot-js-to-sync-with-rails-and-mongoid/
First of all, you need to set idAttribute on model as #SteamDev said.
var CustomerModel = Backbone.Model.extend({
urlRoot: 'http://myresturl/api/CusWeb',
initialize: function(){
},
defaults : {
//UID: "00000000-0000-0000-0000-000000000000",
Sex: 0,
Name: "",
Company: "",
Address: "",
Email: ""
},
idAttribute: "UID" // set "UID" as the alias for "id"
});
Secondly, you don't need to set UID value (neither on defaults of model, nor on model instance).