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).
Related
I'm trying to attach objects from another collection to the Meteor.user collection by a click event. I have a collection with a list of items called "categories" each category has a name field, its that name i want to push into the meteor.user.
Its supposed to work in a way that the user can push as many of these names as they want however its only accepting one entry, and when i click on another name, the new name replaces the old one, instead of being an array. how can i make it so that it can allow many entries?
client/users.js
Template.CategoriesMain.events({
'click .toggle-category': function(e){
//var id = $(e.target).attr('posts.name');
var id = $(e.target).parent().find("a").text();
console.log(id);
e.preventDefault();
Meteor.call('addingCategory', id, function(error, user){ console.log(id)});
}
});
server/users.js
Meteor.methods({
addingCategory: function(name) {
var cats = [{}];
cats.push(name);
console.log(Meteor.userId());
Meteor.users.update({
_id: Meteor.userId()
}, {
$set: {
name: name
}
});
}
});
and this is the user from db.user.find() as you can see with
"name" : "a-reece"
its clearly pushing the name but i cannot add more, i can only replace
{ "_id" : "4CHcZjSD4hCrqweGA", "createdAt" :
ISODate("2016-07-13T21:38:59.505Z"), "services" : { "password" : {
"bcrypt" :
"$2a$10$lKZtrYSMD4EGPj6eamgFDuPZ41Jw52DgivBly3lUYWbGDtfZBg1X." },
"resume" : { "loginTokens" : [ { "when" :
ISODate("2016-07-13T21:38:59.719Z"), "hashedToken" :
"BsqTGedB2FkmSPO3+5I31rOM2+MPtF97Zc9tRQ4pf8Y=" } ] } }, "emails" : [ {
"address" : "mun#les.com", "verified" : false } ], "roles" : [
"discoveror", "yes" ], "isAdmin" : true, "name" : "a-reece" }
how can i add more names instead of replacing?
EDIT
Meteor.methods({
addingCategory: function(name) {
//Meteor.users.update(Meteor.userId(), { $addToSet: { name: name} } );
console.log(Meteor.userId());
//Meteor.users.update(Meteor.userId(), { $set: { "categories": cats }} );
Meteor.users.update({
_id: Meteor.userId()
},
{
$unset: {
name: name
}
},
{
$addToSet: {
name: name
}
});
}
});
ANSWER
Template.CategoriesMain.events({
'click .toggle-category': function(e){
//var id = $(e.target).attr('posts.name');
var ob = $(e.target).parent().find("a").text();
var id = $.makeArray( ob );
console.log(id);
e.preventDefault();
Meteor.call('addingCategory', id, function(error, user){ console.log(id)});
}
});
You're currently doing:
Meteor.users.update({ _id: Meteor.userId() }, { $set: { name: name } });
You have two choices: $push or $addToSet:
Meteor.users.update({ _id: Meteor.userId() }, { $push: { name: name } });
or
Meteor.users.update({ _id: Meteor.userId() }, { $addToSet: { name: name } });
The former pushes onto an array, allowing duplicates, the latter avoids dupes.
You don't need:
var cats = [{}];
cats.push(name);
Ok, so I'm currently going through a course over Backbone.js where I have to create a View with a list of objects, and a delete button, but I keep getting the error (Uncaught TypeError: this.model.each is not a function) where I have indicated below (//THIS IS WHERE THE ERROR IS BEING THROWN). Any help with this is appreciated!
//BACKBONE MODEL//
var Vehicle = Backbone.Model.extend( {
idAttribute: "registrationNumber",
urlRoot: "/api/vehicles",
start: function() {
console.log("Vehicle started.");
}
});
//BACKBONE MODEL//
var Car = Vehicle.extend( {
start: function() {
console.log("Car with registration number XLI887 started.");
},
validate: function(attrs) {
if (!attrs.registrationNumber)
return "Registration number is required.";
}
});
var car = new Car({ registrationNumber: "XLI887", color: "Blue" });
car.start();
//BACKBONE COLLECTION//
var Vehicles = Backbone.Collection.extend({
model: Vehicle,
});
var vehicles = new Vehicles([
new Vehicle({ car: "Car 1", registrationNumber: "XLI887", color: "Blue"}),
new Vehicle({ car: "Car 2", registrationNumber: "ZNP123", color: "Blue"}),
new Vehicle({ car: "Car 3", registrationNumber: "XUV456", color: "Gray"})
]);
var blueCars = vehicles.where({ color: "Blue" });
console.log("Blue Cars", blueCars);
var carRegNumb = vehicles.findWhere({ registrationNumber: "XLI887" });
console.log("Car Reg Numb", carRegNumb);
vehicles.remove(carRegNumb);
vehicles.each(function(vehicle){
console.log(vehicle);
});
//BACKBONE VIEW//
var VehicleView = Backbone.View.extend({
tagName: "li",
className: "vehicle",
id: "registrationNumber",
attributes: {
"data-color": "Blue"
},
render: function(){
this.$el.html(this.model.get("car"));
return this;
},
events: {
"click": "onClick",
"click .delete": "onClickDelete",
},
onClick: function(){
console.log("Delete Clicked");
},
onClickDelete: function(e){
console.log("Delete Clicked");
},
render: function(){
this.$el.html(this.model.get("car") + " <button>Delete</button>");
return this;
}
});
//BACKBONE VIEW//
var VehiclesView = Backbone.View.extend({
tagName: "ul",
className: "vehicle",
id: "registrationNumber",
attributes: {
"data-color": "Blue"
},
render: function(){
var self = this;
this.model.each(function(vehicle){ //THIS IS WHERE THE ERROR IS BEING THROWN
var vehiclesview = new VehiclesView({ model: car });
self.$el.append(vehiclesview.render().$el);
});
return this;
}
});
var vehicles = new Vehicles([
new Vehicle({ car: "Car 1", registrationNumber: "XLI887" }),
new Vehicle({ car: "Car 2", registrationNumber: "ZNP123" }),
new Vehicle({ car: "Car 3", registrationNumber: "XUV456" })
]);
var vehicleView = new VehicleView({ el: "#vehicles", model: car });
vehicleView.render();
var vehiclesView = new VehiclesView({ el: "#vehicles", model: car});
vehiclesView.render();
It seems to me that you get the error because you're passing in a model instance instead of a collection instance to your vehiclesView. Because the car model instance is not an array, you can't iterate over it using each().
Also I believe you're mixing up your model- and collection views. Your vehiclesView is essentially a collection view and should receive a collection of models. It's job is then to instantiate, render and append a vehicleView (model view) for each Vehicle model in your Vehicles collection.
// Vehicles Collection View.
var VehiclesView = Backbone.View.extend({
tagName: 'ul',
className: 'vehicle',
id: 'registrationNumber',
attributes: {
data-color: 'Blue'
},
render: function () {
// This is a collection view, therefore access your data by
// referencing `this.collection` and NOT `this.model`.
this.collection.each(function (vehicleModel) {
// Instantiate a model view for each model in your collection.
var vehicleView = new VehicleView({
model: vehicleModel
});
// Render and append the `vehicleView`
this.$el.append(vehicleView.render().$el);
}, this);
return this;
}
});
Then make sure to instantiate a collection using your models and instantiate your collection view by passing said collection into the collection view.
// Instantiate a collection.
var vehicles = new Vehicles([
new Vehicle({ car: 'Car 1', registrationNumber: 'XLI887' }),
new Vehicle({ car: 'Car 2', registrationNumber: 'ZNP123' }),
new Vehicle({ car: 'Car 3', registrationNumber: 'XUV456' })
]);
// Pass the collection to the vehicles collection view.
var vehiclesView = new VehiclesView({
collection: vehicles // Passing in a collection and NOT a model.
});
// Render the vehicles collection view.
vehiclesView.render();
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({})
})()
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>
User Model
define(
[
'backbone'
],
function (Backbone) {
return Backbone.Model.extend({
url: '/proxy.php/users.json',
defaults: {
'first_name': '',
'last_name': '',
'work_email': ''
},
validation: {
first_name: {
required: true,
msg: 'Please enter a first name'
},
last_name: {
required: true,
msg: 'Please enter a last name'
},
work_email: {
required: true,
msg: 'Please enter a valid email'
}
}
});
}
);
View save data
onSave: function (ev) {
ev.preventDefault()
var details = $('.edit-user-form').serializeObject()
var object = new User()
return object.save(details, {
success: function (response) {
console.log(response, 'response')
}
})
},
details =
{first_name: "", last_name: "", birthdate: "", job_title: "", job_start_date: ""…}
birthdate: ""
first_name: ""
job_probation_ends: ""
job_start_date: ""
job_title: ""
last_name: ""
personal_address: ""
personal_email: ""
personal_phone_number: ""
work_address: ""
work_email: ""
work_phone_number: ""
The problem, the request sent by Backbone sends Form Data as:
model:{"first_name":"","last_name":"","work_email":"","birthdate":"","job_title":"","job_start_date":"","job_probation_ends":"","work_address":"","work_phone_number":"","personal_email":"","personal_address":"","personal_phone_number":""}
Why is it making the attributes a sub object of model? I would like the attributes sent as the root.
If you want to modify the structure of the data you send to the server, then override the toJSON method for your model:
toJSON: function () {
return { // structure the model as you wish here };
}