Backbone Association not working with fetch - backbone.js

I am using Backbone-Associations from
github-Backbone associations
https://github.com/dhruvaray/backbone-associations
for nested models to work with backnone.
I am getting an error while calling fetch() on a model. the response json from server exactly matches the model definitions. i cant figure out what i am missing...
Versions:
Backbone: 0.9.2
Backbone-associations: 0.2.0
TypeError: this.attributes[relationKey].off is not a function
this.attributes[relationKey].off("all");
//this is the code i am using..
var ProductVariation = Backbone.AssociatedModel.extend({
defaults: {
ImageUrl:'',
Desc:''
}
});
var Product = Backbone.AssociatedModel.extend({
relations: [{
type: Backbone.Many,
key: 'ProductVariations',
relatedModel: ProductVariation
}],
url: '/GetProductById',
defaults: {
CategoryId: 0,
ProductVariations: [],
Summary: ''
}
});
am i missing something? any help appreciated...

Oops it's my mistake...
Actually I was using an old version of BackboneJS, but thinking that I was using the latest..
Which doesn't have off and on methods on a collection, instead they use bind and unbind respectively.
Replacing the old one with new one is the fix.

Related

Backbone + Firebase Collection

I'm building a little app and can't figure out why I'm getting an error when trying to add to a collection. Here's the code:
var PollCollection = Backbone.Firebase.Collection.extend({
model: Poll,
url: 'https://***.firebaseio.com/polls',
});
var Poll = Backbone.Model.extend({
defaults: {
title: 'title',
}
});
var pollCollection = new PollCollection();
pollCollection.create({title: "test"});
Any ideas? Thanks!
If I move the model up above the collection everything works fine

backbone-relational: usage with standalone model without relations

I am using backbone-relational. The usage for a onetomany model works fine.
But I am having troubles using backbone-relational for a single/standalone model:
window.BeerOnlineShopPosition = Backbone.RelationalModel.extend({
urlRoot:"../api/beeronlineshoppositions",
idAttribute: 'id',
relations: [
],
defaults:{
"id":null,
"position_amount":""
}
});
window.BeerOnlineShopPositionCollection = Backbone.Collection.extend({
model:BeerOnlineShopPosition,
url:"../api/beeronlineshoppositions"
});
in main i have:
beeronlineshopproductDetails:function (id) {
var beeronlineshopproduct = BeerOnlineShopProduct.findOrCreate(id);
beeronlineshopproduct.fetch();
var beeronlineshopproduct_view = new BeerOnlineShopProductView({el: $('#content'), model: beeronlineshopproduct});
},
So, when jump to an existing records (...beeronlineshop/beeronlineshopproducts/#4), nothing happens. But debugging shows, that the fetch is executed and the view gets loaded. but the view is not rendered somehow.
When I refresh (f5), the view gets rendered correctly.
As mentioned the whole thing works for one-to-many model, so my question is:
did i make some trivial syntax-error on the model part?... or is there any other obvious reason for the troubles i have?
It may be because of the asynchronous request created by findOrCreate. beeronlineshopproduct.fetch() is making a request to the server but the view is being rendered before the server returns with a response.
You have two options. You can pass in the rendering of the view as a callback upon fetch's success like so:
beeronlineshop.fetch({
success: function() {
var beeronlineshopproduct_view = new BeerOnlineShopProductView({el: $('#content'), model: beeronlineshopproduct})
});
Or you can pass an initializer in your BeerOnlineShopProductView that listens to the its model syncing with the server, and calls for the view to re-render itself, like so:
window.BeerOnlineShopProductView = Backbone.View.extend({
initialize: function() {
this.listenTo (this.model, "sync", this.render)
},
})

Backbone.js | Filter Collection data

I am trying to filter some data from my collection. I am using where method for the job but it is returning an empty array. Here is the code.
Model:
return Backbone.Model.extend({
urlRoot: server_url + "tasks",
defaults: {
'id': null,
'title': '',
'description': '',
'deadline': null,
'priority': 1,
'status': 1,
'key': '',
'priority_name': '',
'status_name': ''
}
});
Collection:
return Backbone.Collection.extend({
url: server_url + "tasks",
model: TaskModel
});
And using it like:
var taskList = new TaskList();
taskList.fetch({
data: $.param({key: $.cookie('SID')}),
success: function(collection, response){
if(response.error){
window.location.replace('#logout');
}
}
});
taskList.where({status: 1});
taskList have all the data in it. It is not empty.
I have tried many combinations but hard luck every time.
I have also consulted from following posts but same result.
Backbone collection where clause with OR condition
Filter backbone collection by attribute value
toJSON on Backbone.Collection#where?
What I am missing here?
There doesn't appear to be anything wrong with the code you've posted, but then you're not showing us the population of your Collection. Remember that Backbone.Collection.where simply takes a literal and returns an array of matched Backbone.Model's. I have taken your code and simplified it to demonstrate a working example: http://jsfiddle.net/CK3Hz/
Edited as per comments below
Backbone.Collection.fetch's success callback receives (collection, response, options) arguments. If you are to perform the where on collection, this should work.
I have provided another jsfiddle to demonstrate using event propagation which I assume is your end goal.

Building search application form and displaying result in grid upon submit in extjs-mvc

I am trying to build a search application using ExtJS. I have created dummy form to search for personal details. I have a php script connected to mysql DB. I am able to pass form parameters to php and able to get the return result in msg box. but I am not understanding how to pass it to store and display the same in grid in MVC. I have tried to pass the return data of php to store and then called Grid (List.js) in controller. still did not work. I have shown all the codes that i have used to do this.Another doubt which i have, is that essential to use proxy part of code (i.e url:app/scripts/Info.php) in both store and onSearchButtonClick function in controller? as I can directly pass the return values to store from onSearchButtonClick function, I hope it is not essential to connect php script in both places. However, it would be really nice experts clarify this.
Following is my store:
Ext.define('App.store.Info', {
extend: 'Ext.data.Store',
model: 'App.model.Info',
alias: 'widget.infostore',
pageSize : 50,
autoLoad : false,
remoteFilter: true,
proxy :{
type : 'ajax',
url : 'app/scripts/Info.php',
reader : {
type : 'json',
root : 'result',
successProperty : 'success'
}
},
listeners: {
load : function(store) {
store.each(function(record) {
record.commit();
});
}
}
});
My model looks perfect, simply to reduce somuch code I havent put here
Here is my grid:
Ext.define('App.view.info.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.infolist',
store : 'Info',
initComponent: function(){
this.columns = [
{header:'PID',dataIndex:'pid'},
{header:'Name',dataIndex:'name'},
{header:'Address', dataIndex:'address'},
{header:'Contact', dataIndex:'contact'}
];
this.callParent(arguments);
}
});
This is what my php script returns:
{'success':true, 'result':{'pid':'100','name':'Suman','address':'Bangalore','contact':'suman#xyz.com'}}
Here is controller:
Ext.define('App.controller.Info', {
extend: 'App.controller.Base',
models: ['Info'],
stores: ['Info'],
views: [
'info.Index',
'info.List'
],
refs: [{ref: 'info',selector: 'info'}],
init: function(){
console.log('Main controller init');
this.control({
'button[action=search]':{
click: this.onSearchButtonClick
}
});
},
onSearchButtonClick:function(){
var form = Ext.getCmp('ppanel');
if(form.getForm().isValid()){
Ext.Ajax.request({
waitMsg: 'Searching...',
method: 'POST',
url: 'app/scripts/Info.php',
params: {
searchData: Ext.encode(form.getValues())
},
scope:this,
success: this.onSearchSuccess,
failure: this.onSearchFailure
//Ext.MessageBox.alert("XXXXX","dat");
});
}
},
onSearchSuccess: function(response){
var gData = Ext.JSON.decode(response.responseText);
//var grid = Ext.widget('infolist'); //not working -need help
this.getInfoStore().load(gData);
//Ext.getCmp().setActiveItem('infolist'); //not working-need help
//this.getViewport().getLayout().setActiveItem('infolist'); //not working need help
Ext.MessageBox.alert("XXXXX",response.responseText); //works
},
onSearchFailure: function(err){
Ext.MessageBox.alert('Status', 'Error occured during searching...');
}
});
I hope I have provided required information to understand the problem. Looking forward some sort of help.
The problem is that you have two instances of the store, one in grid and one in controller.
If you want a single instance store (like it seems you want) you have two options:
Add it to your application
Assign a storeId to your store definition.
(if you already added that store to your application, ignore the above text)
Or, better yet, do not work directly with the store but with your grid, like this:
First add a ref to your view->grid in your controller:
refs: [{ref: 'info',selector: 'info'},{selector:'infolist', ref:'infoGrid'}]
And then, in your onSearchSuccess handler, instead of calling: this.getInfoStore().load(gData); you should call: this.getInfoGrid().getStore().loadData(gData);
BTW: this.getInfoStore().load(gData); will never load an array of data or a record, for that you should use: this.getInfoStore().loadData(gData);
Hope this gets you in the right track.

Creating nested models with backboneJS + backbone-relational + requireJS

I am new to BackboneJS and I am stuck with nested relations using Backbone-relational Model with RequireJS -I think I runned into circular issues. Any help will be highly appreciated!
I have the following model and collection:
/* Module Model at models/module*/
define([
'jquery',
'underscore',
'backbone',
'backboneRelational',
], function($, _, Backbone) {
var ModuleModel = Backbone.RelationalModel.extend({
urlRoot: 'api/module',
_radius: 50,
relations: [{
type: Backbone.HasMany,
key: 'children',
relatedModel: 'ModuleModel',
collectionType: 'ModuleCollection',
reverseRelation: {
key: 'parent_id',
includeInJSON: 'id'
}
}],
url: function() {
return this.id? 'api/module/' + this.id : 'api/module';
}
});
return ModuleModel;
});
/* Module Collection */
define([
'jquery',
'underscore',
'backbone',
'models/module'
], function($, _, Backbone, ModuleModel) {
var ModuleCollection = Backbone.Collection.extend({
model: ModuleModel,
url: 'api/modules'
});
return ModuleCollection;
});
When I initialize the object ModuleModel, it throws the following error:
Relation=child; no model, key or relatedModel (function (){ parent.apply(this, arguments); }, "children", undefined)
Could you point me to the right direction?
This looks like a scoping issue. During initialization of ModuleModel it wants to create a hasMany relation with itself, but it can't find itself and it will give you grief in form of said error:
http://jsfiddle.net/yNLbq
Once the object is reachable from the current scope things start to work out:
http://jsfiddle.net/jDw5e
A possible solution would be to give models and collection a namespace for themselves which can be reached from the current scope.
Hope this helps.
I came across this problem from here:
RequireJS + BackboneRelational + Self-Referential. He seems to have inherited some of his problems from this thread so I thought I might add my dime.
First, since you're using RequireJS, there are no global variables. You can't simply supply the name of the object, you need to supply actual object references for relatedModel and collectionType.
Your trickiest issue is that ModuleModel's relatedModel is actually ModuleModel itself, which won't be defined when you assign it to relatedModel (using the AMD model). You have to defer assignment until after ModuleModel is assigned.
Finally, you need to resolve the circular reference. dokkaebi is on the right track when he suggests using exports, but his implementation actually misuses exports. When exporting, attach the object directly to exports as he suggests, but when you import it you need to reference the module to use it, not exports.
This should work:
ModuleModel.js
define(['exports', 'ModuleCollection'], function (exports, Module) {
'use strict';
var ModuleModel = Backbone.RelationalModel.extend({
urlRoot: 'api/module',
_radius: 50,
relations: [{
type: Backbone.HasMany,
key: 'children',
// ModuleModel is undefined; this line is useless
// relatedModel: ModuleModel,
// no globals in require; must use imported obj ref
collectionType: Module.Collection,
reverseRelation: {
key: 'parent_id',
includeInJSON: 'id'
}
}],
url: function() {
return this.id? 'api/module/' + this.id : 'api/module';
}
});
// Now that `ModuleModel` is defined, we can supply a valid object reference:
ModuleModel.prototype.relations[0].relatedModel = ModuleModel;
// Attach `Model` to `exports` so an obj ref can be obtained elsewhere
exports.Model = ModuleModel;
});
ModuleCollection.js
define(['exports', 'ModuleModel'], function(exports, Module) {
'use strict';
var ModuleCollection = Backbone.Collection.extend({
// must reference the imported Model
model: Module.Model,
url: 'data.php' // <-- or wherever
});
// Attach `Collection` to `exports` so an obj ref can be obtained elsewhere
exports.Collection = ModuleCollection;
});
Main.js
define(['ModuleCollection'], function(Module) {
'use strict';
var modules = new Module.Collection();
modules.fetch().done(function() {
modules.each(function(model) {
console.log(model);
});
});
});
From a comment in backbone-relational.js v0.5.0 (line 375):
// 'exports' should be the global object where 'relatedModel' can be found on if given as a string.
If you require the special 'exports' value as a dependency in your define call, and then place your module onto the exports object before you return, then you can reference that module as a string or as a member of exports.
in ModuleModel.js:
define(['exports', 'use!backbone', 'use!backbone-relational'], function(exports, Backbone) {
var ModuleModel = Backbone.RelationalModel.extend({
relations: [
{
type: Backbone.HasMany,
key: 'groups',
relatedModel: 'ModuleModel',
collectionType: 'ModuleCollection'
}
]
});
exports.ModuleModel = ModuleModel;
return ModuleModel;
});
and in ModuleCollection.js:
define(['exports', 'use!backbone'], function(exports, Backbone) {
var ModuleCollection = Backbone.RelationalModel.extend({
url: '/api/v1/module/';
model: exports.ModuleModel;
});
exports.ModuleCollection = ModuleCollection;
return ModuleCollection;
});
I ran into the same problem a while back and followed the approach used by Andrew Ferk for his question: Backbone-relational submodels with RequireJS. The problem arises because you're defining models as Require modules so they don't exist on the global scope, where backbone-relational can look for them. Instead of using global scope (beats the purpose of Require) or exports (bit tricky with the relations), you can define a scope for your models and tell backbone-relational to look for models in it, with addModelScope().
//modelStore.js - A scope in which backbone-relational will search for models
//Defined separately so you can access 'modelStore' directly for your models instead of requiring 'app' every time.
define(['app'], function(app) {
app.modelStore = {};
Backbone.Relational.store.addModelScope(app.modelStore);
return app.modelStore;
}
By the way you should shim your Backbone dependency and not need to require jQuery and Underscore for it.
//ModuleModel (The ModuleModel module. Nice.)
define(['modelStore', 'backbone', 'backboneRelational'], function(modelStore, Backbone {
modelStore.ModuleModel = Backbone.RelationalModel.extend({
relations: [
{
type: Backbone.HasMany,
key: 'groups',
relatedModel: 'ModuleModel', //Not modelStore.ModuleModel
collectionType: 'ModuleCollection'
}
]
});
return modelStore.ModuleModel;
});
Kinda late for this now but hope it helps others.

Resources