Update model with data retrieved from backbone.sync call - javascript

I have a backbone model similar to this.
User = Backbone.Model.extend({
defaults: {
id: null,
name: '',
groups: []
},
addGroup: function(group) {
return this.sync(
'update',
this,
{url: this.url() + 'add_group', data: 'group=' + group}
);
}
}
UserCollection = Backbone.Collection.extends({
model: User,
url: '/api/users'
});
The purpose behind this call is that adding the permission triggers all sorts of backend checks and other changes. The actual code, which I'm trying to not to expose here, demonstrates the need better.
The /api/users/add_group endpoint returns a new representation of the Users model, which I wish to have applied to the model with all of the appropriate events triggered. The best work-around I could find is this.
User = Backbone.Model.extend({
defaults: {
id: null,
name: '',
groups: []
},
addGroup: function(group) {
model = this;
return this.sync(
'update',
this,
{
url: this.url() + 'add_group',
data: 'group=' + group,
success: function() {model.fetch();}
}
);
}
}
However, it feels like there is probably a better solution where I can call arbitrary endpoints and have the model updated with the returned data.

Related

Backbone relational model saving error

I get the error, when I try to save the model with .save()
Converting circular structure to JSON
The funny thing is that modelInstance.toJSON() works just fine.
The error is thrown at backbone.js line 1148
which is:
params.data = JSON.stringify(options.attrs || model.toJSON(options));
Here is how I've setup of the model:
var Clip = Backbone.RelationalModel.extend({
idAttribute: "mediaItemId",
defaults: {
node: {}
}
});
var clipCollection = Backbone.Collection.extend({
model: Clip
});
var mainModel = Backbone.RelationalModel.extend({
url: '/api/v0/videostate',
relations: [
{
type: Backbone.HasMany
,key: 'videoCollection'
,relatedModel: Clip
,collectionType: clipCollection
,includeInJSON: Clip.idAttribute
,reverseRelation: {
key: 'parent',
includeInJSON: Clip.idAttribute
}
}
],
});
var modelInstance = new mainModel()
modelInstance.fetch();
The JSON that's loaded into the model:
Change includeInJSON: Clip.idAttribute in reverse relation to includeInJSON: Clip.prototype.idAttribute
Something like this
{
type: Backbone.HasMany
,key: 'videoCollection'
,relatedModel: Clip
,collectionType: clipCollection
,includeInJSON: Clip.prototype.idAttribute
,reverseRelation: {
key: 'parent',
includeInJSON: Clip.prototype.idAttribute
}
}
Created a JSFiddle with above code , http://jsfiddle.net/ravikumaranantha/PuLxQ/6/, it doesn't throw any error.
var Clip = Backbone.RelationalModel.extend({
idAttribute: "mediaItemId",
defaults: {
node: {} //could be problem here
}
});
I just sense problem could be (not sure) with having an object in defaults map, you should avoid using objects/arrays in defaults, they will get shared across all instances. If you can post response from fetch call, that should help us debug it further.

Sencha touch store - phantom data

I created a model like
Ext.define('MyApp.model.ContainerDetailsModel', {
extend: 'Ext.data.Model',
alias: 'model.ContainerDetailsModel',
config: {
fields: [
{
name: 'id',
allowNull: false,
type: 'string'
},
{
name: 'container_types_id',
type: 'string'
}
]
}
});
and a store like this
Ext.define('MyApp.store.ContainerDetailsStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.ContainerDetailsModel'
],
config: {
model: 'MyApp.model.ContainerDetailsModel',
storeId: 'ContainerDetailsStore',
proxy: {
type: 'ajax',
enablePagingParams: false,
url: 'hereIsServiceUrl',
reader: {
type: 'json'
}
}
}
});
Now somewhere in application I tried to get one record like:
var detailsStore = Ext.getStore("ContainerDetailsStore");
detailsStore.load();
var detailsRecord = detailsStore.last();
But it gaves me undefined. The json returned by service is ok, it use it in different place as source for list. I already tried to change allowNull to true, but there is no null id in source. I tried set types to 'int' with the same result.
So I have tried
console.log(detailsStore);
Result is like this (just important values):
Class {
...
loaded: true,
data: Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
...
},
...
}
In the same place
console.log(detailsStore.data);
returns (as it should):
Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
but (next line)
console.log(detailsStore.data.all);
returns
[]
And it's empty array. When i try any methods from the store it says the store is empty.
I wrote console.log() lines one after another - so for sure it doesn't change between them (I try it also in different order or combinations).
My browser is Google Chrome 23.0.1271.97 m
I use Sencha from https://extjs.cachefly.net/touch/sencha-touch-2.0.1.1/sencha-touch-all-debug.js
How can I take a record from that store?
store.load() Loads data into the Store via the configured proxy. This uses the Proxy to make an asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved instances into the Store and calling an optional callback if required. The method, however, returns before the datais fetched. Hence the callback function, to execute logic which manipulates the new data in the store.
Try,
detailsStore.load({
callback: function(records, operation, success) {
var detailsRecord = detailsStore.last();
},
scope: this
});

backbone fetch complicate structure

I have 3 models on backbone:
var Level1Model = Backbone.Model.extend({
defaults: {
level2Collection: null
}
});
var Level2Model = Backbone.Model.extend({
defaults: {
level3Collection: null,
text: null
}
});
var Level3Model = Backbone.Model.extend({
defaults: {
text: null
}
});
I have two REST services (urls):
1. One that gets Level1Model id and returns Level1Model with Level2Model and id's of Level3.
For example:
{
Level2Collection: [
{
text: "aaa",
Level3Collection: [ {id:1}, {id:2}, {id:3} ]
},
{
text: "bbb",
Level3Collection: [ {id:4}, {id:5} ]
}
]
}
2. One that gets Level3Model id and returns Level3Model data.
I am looking a way to fetch all the data structure by doing:
var level1Ins = new Level1Model({id:123});
level1Ins.fetch({
success: function() {
doSomething();
}
});
I am really confused of how to do it. For example, I don't know how can I fill the Level3Collection and also call doSomething() when success loading all elements.
How can I load the entire level1 instance?
You should try Backbone Relational. It makes this kind of thing very easy to work with.

ExtJS store/proxy doesn't send delete method to server

I'm trying to create simple ExtJs application that manages Users and User's Roles. Set of REST services provide this functionality on back end.
When I assign a new Role to a User, appropriate data store sends POST (create) requests to the service. However when I remove existing Role from a User, it's removed only from store locally without sending DELETE request to the service.
Here is my code:
Model:
Ext.define('UserRole', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Id', mapping: "Id" },
{ name: 'RoleId', mapping: "RoleId" },
{ name: 'UserId', mapping: "UserId" }
]
});
Store With proxy:
Ext.define('UserRoleStore', {
extend: 'Ext.data.Store',
model: 'UserRole',
autoload: false,
proxy: {
type: 'ajax',
reader: {
type: 'json',
root: 'd.results'
},
api: {
read: '/accessmanager.svc/Users(\'{userid}\')/Roles?$format=json',
create: '/accessmanager.svc/UserRoles?$format=json',
update: '/accessmanager.svc/UserRoles?$format=json',
destroy: '/accessmanager.svc/UserRoles?$format=json'
},
updateApiUrlWithUserId: function (userId) {
this.api.read = this.api.read.replace('{userid}', userId);
}
}
});
Method that based on selected checkboxes updates the UserRole store
var chekboxes = Ext.ComponentQuery.query('userdetails #roleslist')[0];
var selectedUserId = this.selectedUserId;
var selectedUserRoleStore = this.selectedUserRoleStore;
Ext.each(chekboxes.items.items, function (cb) {
var exists = false;
Ext.each(selectedUserRoleStore.data.items, function (cs) {
if (cs.data.RoleId === cb.inputValue) {
exists = true;
}
});
if (cb.getValue() && !exists) {
var newRole = Ext.create('UserRole', { RoleId: cb.inputValue, UserId: selectedUserId });
selectedUserRoleStore.add(newRole);
} else if (exists && !cb.getValue()) {
// delete existing role
var record = selectedUserRoleStore.findRecord("RoleId", cb.inputValue);
selectedUserRoleStore.remove(record);
}
});
selectedUserRoleStore.sync();
Presumably your Id field is assigned on the server end when record is created. Correct? First try to specify idProperty: 'Id' in the model. Default value for this is 'id' but I think these are case sensitive.
Using idProperty ExtJs recognizes records as being 'dirty' and required to be updated on the server end.
The issue is your proxy needs to be a specialized REST type:
proxy: {
type: 'rest',
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.proxy.Rest
Also, you will probably be able to use the buildURL method to replace your own updateAPI... method.

How to get id on a successful model.save()?

Have checked some backbone.js tutorials and can't
understand how to get model id from the server within
the model saving process. I have a model:
var Game = Backbone.Model.extend({
defaults: {
name: '',
releaseDate: ''
},
url: function(){
return '/data.php';
}
});
How to implement getting the id algorithm? It seams to me, there should
be a kind of callback function, but can't realise where to put it.
See Backbone's documentation on model save.
You can pass a success callback function to save, something like this:
var game = new Game({
name: 'Duke Nukem 3D',
releaseDate: '1996'
});
game.save({}, {
success: function(model, response) {
// get model id from response?
}
);

Categories

Resources