backbone.js - model.save() generate wrong PUT url path - javascript

I hate to ask these strange problems but couldn't able to avoid this one.
I have "Option" view with "Option" model passed as a parameter when creating.
var optionView = new OptionView({ model: option });
this.$el.find('div#optionsBoard').append( optionView.render().el );
In this view, when the user clicks on "Vote" button, the "voteCount" attribute of the model will be incremented.
events: { 'click .button-vote': 'processVote' },
processVote: function (e) {
var voteCounted = this.model.get('voteCount');
this.model.set('voteCount', voteCounted++);
console.log(this.model.id); // has a Id value
console.log(this.model.isNew()); // false
this.model.save(); // occurs problem here
e.preventDefault();
},
The problem occurs when I save the model back to the server as following:
PUT http://localhost:13791/api/options/ 404 (Not Found)
Yes, this url actually isn't existed on my REST API server. But I believe the correct path of PUT URL to update the model should be as following:
PUT http://localhost:13791/api/options/id_of_the_entity_to_be_updated
When I test this PUT url (http://localhost:13791/api/options/id_of_the_entity_to_be_updated) with Postman Rest client, it works perfectly.
So I think the problem occurs because Backbone model.save() method does not add the id_of_the_entity_to_be_updated to the PUT url.
Please, suggest me something how should I solve this problem.
As additional description, this is my "option" model setup code.
define([
'backbone'
], function (Backbone) {
var Option = Backbone.Model.extend({
idAttribute: "_id",
defaults: {
name: '',
location: '',
link: '',
voteCount: 0,
expiredDate: Date.now(),
imageName: ''
},
url: '/api/options/',
readFile: function(file) {
var reader = new FileReader();
// closure to capture the file information.
reader.onload = ( function(theFile, that) {
return function(e) {
that.set({filename: theFile.name, data: e.target.result});
that.set({imageUrl: theFile.name});
console.log(e.target.result);
};
})(file, this);
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
});
return Option;
});
Problem found
My bad. In the "Option" model setup, it should be "urlRoot" instead of "url".

In your model you should use urlRoot instead url:
urlRoot: '/api/options/'

Related

Backbone fetch - "url" property or function must be specified error

Pretty new to Backbone, so please mind my ignorance...
I have a simple GallereyModel:
var GalleryModel = Backbone.Model.extend({
defaults : {
id: "",
width: ""
},
url : ""
});
When the model is updated, the function galleryModelUpdate is called
var GalleryView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model, "change", this.galleryModelUpdate);
},
galleryModelUpdate: function(){
console.log("updated gallery model"+this.model.get("id");
if (this.model.get("url")){
console.log("fetching " + this.model.get("url")); // this line prints with the correct url
this.model.fetch({ // this line gives error
success: function(){
console.log("fetched succesfully!");
}
});
}
}
});
I am printing the value of url on the model before fetch is called, so not sure why is it throwing the "url" undefined error?
Many thanks for your help in advance
Either the url or the urlRoot model properties needs to be defined in order for the model to fetch.
You can set your model url to point to the url data attribute:
Backbone.Model.extend({
url: function () {
return this.get('url');
}
});

Data Tables are not loading when i redirect my page using self.do_action in odoo(openERP7) qweb screen

When i redirect my page using self.do_action in odoo(openERP7) it is not loading Data Tables in the new page.
In other pages it was working fine. But in a particular page if i redirect using this self.do_action is not working. But self.act_window is working fine in the same page.
If any one faced this same issue please let me know.
Update:I found a similarity of problems in my code. I have a model like performance.review and some other models also. All the self.do_action used in this model is not loading Data tables properly. But other model screens does perfectly.
Is there any relation between model extension and using self.do_action?
Here is my code,
module.ReviewForm= instance.web.Widget.extend({
events: {
'click #review_tree_view':'load_tree_view',
},
load_tree_view: function (event) {
var self = this;
self.do_action({
type: 'ir.actions.client',
tag: "performance.review",
name:'Tree view',
target: 'current',
});
},
In the javascript file, you could add an event to a buttons class name like this:
bind_events: function () {
this.$('.oe_btn_class_name').on('click', this.on_call_new_view_function);
},
Then the "on_call_new_view_function" is called when a click event occurs and opens the new view like this:
on_call_new_view_function: function () {
var self = this;
// you can pass in other data using the context dictionary variable
var context = {
'id': this.id,
};
// the action dictionary variable sends data in the "self.do_action" method
var action = {
type: 'ir.actions.act_window',
res_model: 'model.name',
view_id: 'view_id',
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: context,
};
// self.do_action accepts the action parameter and opens the new view
self.do_action(action);
},
Actually this is a small mistake done by myself. Im using the same model for many qweb screens, and each time Im rendering form view using self.do_action I did't emptying the existing tree view.
It can be easily done by adding this line.
Now data tables loading properly and perfectly.
load_tree_view: function (event) {
var self = this;
self.$el.empty();
self.do_action({
type: 'ir.actions.client',
tag: "performance.review",
name:'Tree view',
target: 'current',
});
},

Backbone model is not saved

var elementUrlRoot = api_url + '/elements';
var elementModel = Backbone.Model.extend({
'idAttribute': '_id' //mongoDB
, 'urlRoot': elementUrlRoot
, defaults: {
"signature": "",
"group": 0
}//defaults
});
var elementCollection = Backbone.Collection.extend({
model: elementModel
, 'url': elementUrlRoot
});
var testmodel = new elementModel({DOM_id: 111});
testmodel.save({signature: "test"},
{
error: function (model, response, options) {
console.log('test model save error:', response);
},
success: function () {
console.log('test model save success');
}
}
);
My backbone model is not saved to the server when I update it.
I have set the urlRoot attribute of the Model (which according to the documentation should not be necessary). But there are still no HTTP requests being issued.
Update:
I have added a success method in the callback. It is being executed.
But there are no requests being sent to the server.
Update:
I found the error. I had added this code to save a whole collection.
Backbone.Collection.prototype.syncCollection = function (options) {
console.log('syncing the collection');
Backbone.sync("create", this, options);
};
It worked and I was able to save collections with it.
But it seems to have caused a problem with saving individual models. Requests are issued when I removed it.
Your urlRoot is needed because your model is not part of a collection.
Try unquoting your urlRoot attribute on the left side of the assignment
http://backbonejs.org/#Model-urlRoot

Ember Data belongsTo async relationship omitted from createRecord() save() serialization

Edit 11/16/14: Version Information
DEBUG: Ember : 1.7.0 ember-1.7.0.js:14463
DEBUG: Ember Data : 1.0.0-beta.10+canary.30d6bf849b ember-1.7.0.js:14463
DEBUG: Handlebars : 1.1.2 ember-1.7.0.js:14463
DEBUG: jQuery : 1.10.2
I'm beating my head against a wall trying to do something that I think should be fairly straightforward with ember and ember-data, but I haven't had any luck so far.
Essentially, I want to use server data to populate a <select> dropdown menu. When the form is submitted, a model should be created based on the data the user chooses to select. The model is then saved with ember data and forwarded to the server with the following format:
{
"File": {
"fileName":"the_name.txt",
"filePath":"/the/path",
"typeId": 13,
"versionId": 2
}
}
The problem is, the typeId and versionId are left out when the model relationship is defined as async like so:
App.File = DS.Model.extend({
type: DS.belongsTo('type', {async: true}),
version: DS.belongsTo('version', {async: true}),
fileName: DS.attr('string'),
filePath: DS.attr('string')
});
The part that is confusing me, and probably where my mistakes lie, is the controller:
App.FilesNewController = Ember.ObjectController.extend({
needs: ['files'],
uploadError: false,
// These properties will be given by the binding in the view to the
//<select> inputs.
selectedType: null,
selectedVersion: null,
files: Ember.computed.alias('controllers.files'),
actions: {
createFile: function() {
this.createFileHelper();
}
},
createFileHelper: function() {
var selectedType = this.get('selectedType');
var selectedVersion = this.get('selectedVersion');
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path'
});
var gotDependencies = function(values) {
//////////////////////////////////////
// This only works when async: false
file.set('type', values[0])
.set('version', values[1]);
//////////////////////////////////////
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
this.set('uploadError', true);
}.bind(this);
file.save().then(onSuccess, onFail);
}.bind(this);
Ember.RSVP.all([
selectedType,
selectedVersion
]).then(gotDependencies);
}
});
When async is set to false, ember handles createRecord().save() POST requests correctly.
When async is true, ember handles GET requests perfectly with multiple requests, but does NOT add the belongsTo relationships to the file JSON during createRecord().save(). Only the basic properties are serialized:
{"File":{"fileName":"the_name.txt","filePath":"/the/path"}}
I realize this question has been asked before but I have not found a satisfactory answer thus far and I have not found anything that suits my needs. So, how do I get the belongsTo relationship to serialize properly?
Just to be sure that everything is here, I will add the custom serialization I have so far:
App.ApplicationSerializer = DS.RESTSerializer.extend({
serializeIntoHash: function(data, type, record, options) {
var root = Ember.String.capitalize(type.typeKey);
data[root] = this.serialize(record, options);
},
keyForRelationship: function(key, type){
if (type === 'belongsTo') {
key += "Id";
}
if (type === 'hasMany') {
key += "Ids";
}
return key;
}
});
App.FileSerializer = App.ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
type: { serialize: 'id' },
version: { serialize: 'id' }
}
});
And a select:
{{ view Ember.Select
contentBinding="controller.files.versions"
optionValuePath="content"
optionLabelPath="content.versionStr"
valueBinding="controller.selectedVersion"
id="selectVersion"
classNames="form-control"
prompt="-- Select Version --"}}
If necessary I will append the other routes and controllers (FilesRoute, FilesController, VersionsRoute, TypesRoute)
EDIT 11/16/14
I have a working solution (hack?) that I found based on information in two relevant threads:
1) How should async belongsTo relationships be serialized?
2) Does async belongsTo support related model assignment?
Essentially, all I had to do was move the Ember.RSVP.all() to after a get() on the properties:
createFileHelper: function() {
var selectedType = this.get('selectedType');
var selectedVersion = this.get('selectedVersion');
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path',
type: null,
version: null
});
file.set('type', values[0])
.set('version', values[1]);
Ember.RSVP.all([
file.get('type'),
file.get('version')
]).then(function(values) {
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
alert("failure");
this.set('uploadError', true);
}.bind(this);
file.save().then(onSuccess, onFail);
}.bind(this));
}
So I needed to get() the properties that were belongsTo relationships before I save the model. I don't know is whether this is a bug or not. Maybe someone with more knowledge about emberjs can help shed some light on that.
See the question for more details, but the generic answer that I worked for me when saving a model with a belongsTo relationship (and you specifically need that relationship to be serialized) is to call .get() on the properties and then save() them in then().
It boils down to this:
var file = this.store.createRecord('file', {
fileName: 'the_name.txt',
filePath: '/the/path',
type: null,
version: null
});
// belongsTo set() here
file.set('type', selectedType)
.set('version', selectedVersion);
Ember.RSVP.all([
file.get('type'),
file.get('version')
]).then(function(values) {
var onSuccess = function() {
this.transitionToRoute('files');
}.bind(this);
var onFail = function() {
alert("failure");
this.set('uploadError', true);
}.bind(this);
// Save inside then() after I call get() on promises
file.save().then(onSuccess, onFail);
}.bind(this));

Not fetching correct url issue

I have a backboneJS app that has a router that looks
var StoreRouter = Backbone.Router.extend({
routes: {
'stores/add/' : 'add',
'stores/edit/:id': 'edit'
},
add: function(){
var addStoresView = new AddStoresView({
el: ".wrapper"
});
},
edit: function(id){
var editStoresView = new EditStoresView({
el: ".wrapper",
model: new Store({ id: id })
});
}
});
var storeRouter = new StoreRouter();
Backbone.history.start({ pushState: true, hashChange: false });
and a model that looks like:
var Store = Backbone.Model.extend({
urlRoot: "/stores/"
});
and then my view looks like:
var EditStoresView = Backbone.View.extend({
...
render: function() {
this.model.fetch({
success : function(model, response, options) {
this.$el.append ( JST['tmpl/' + "edit"] (model.toJSON()) );
}
});
}
I thought that urlRoot when fetched would call /stores/ID_HERE, but right now it doesn't call that, it just calls /stores/, but I'm not sure why and how to fix this?
In devTools, here is the url it's going for:
GET http://localhost/stores/
This might not be the answer since it depends on your real production code.
Normally the code you entered is supposed to work, and I even saw a comment saying that it works in a jsfiddle. A couple of reasons might affect the outcome:
In your code you changed the Backbone.Model.url() function. By default the url function is
url: function() {
var base =
_.result(this, 'urlRoot') ||
_.result(this.collection, 'url') ||
urlError();
if (this.isNew()) return base;
return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
},
This is the function to be used by Backbone to generate the URL for model.fetch();.
You added a custom idAttribute when you declared your Store Model to be like the one in your DB. For example your database has a different id than id itself, but in your code you still use new Model({ id: id }); when you really should use new Model({ customId: id });. What happens behind the scenes is that you see in the url() function it checks if the model isNew(). This function actually checks if the id is set, but if it is custom it checks for that:
isNew: function() {
return !this.has(this.idAttribute);
},
You messed up with Backbone.sync ... lots of things can be done with this I will not even start unless I want to make a paper on it. Maybe you followed a tutorial without knowing that it might affect some other code.
You called model.fetch() "a la" $.ajax style:
model.fetch({
data: objectHere,
url: yourUrlHere,
success: function () {},
error: function () {}
});
This overrides the awesomeness of the Backbone automation. (I think sync takes over from here, don't quote me on that).
Reference: Backbone annotated sourcecode

Categories