I have a javascript code as below :
p.onRowSelectExtraListener = function(e)
{
var that = e.data.that;
that.actions.selectedRows = that.table.getSelectedRows();
var selected = [];
var disableoption = false;
$('#checkboxes input:checked').each(function() {
selected.push($(this).attr('statusid'));
});
$.each(selected, function(index, value) {
if (value == 27)
{
disableoption = true;
return false;
}
console.log(disableoption);
if(disableoption === true)
{
console.log("calling another function");
//call p.getRowActions and disable the 3rd menu item/button.option.
}
});
};
p.getRowActions = function()
{
var that = this;
var addToGroupOptions = this.data.group.slice(0);
console.log("in get row actions");
if (this.canUnlock == 0)
{
console.log("In Super-IF loop");
}
addToGroupOptions.unshift({id: 'new', name: 'new group'});
//TODO translate
return [
{
option: {id: '4', name: 'add to group'},
options: addToGroupOptions,
type: 'ajax',
func: function(selectedRows, group)
{
that.onAddToGroup(selectedRows, group);
}
},
{
option: {id: '2', name: 'change rights issue'},
type: 'ajax',
func: function(selectedRows, rights) {
that.onChangeRights(selectedRows, rights);
}
},
{
option: {id: '1', name: 'change status'},
options: this.data.status,
type: 'ajax',
func: function(selectedRows, status) {
that.onChangeStatus(selectedRows, status);
}
},
{
option: {id: '3', name: 'edit'},
type: 'ajax',
func: function(selectedRows, edit) {
that.onChangeEdit(selectedRows, edit);
}
}
];
};
Now out of these two functions, the second one is called/executed first when I load my page.
Hence I can see console.log("in get row actions"); printed as well as the 4 options under return[] statement present as buttons in my application.
Now my requirement is :
To disable the 3rd option(the option with id:1 name:change status whenever disableoption = true will be set in the 1st function.
How is that possible ?
How can I access and remove the property defined in diffrent function ?
Thanks in advance.
p.getRowActions returns an array, access the objects within the array and change the property of the object you want, once the object is modified you can reassemble the array with the new object (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) and then return this corrected array to the component that consumes its data to add the HTML objects to the DOM.
Another option is to insert a callback function at the end of the function that receives the array returned from p.getRowActions so you can edit the object in the DOM after it is created/rendered.
UPDATE (pseudo-code to illustrate solution):
function some_function_that_consumes_getRowActions_that_is_somewhere_else_that_I_dont_know() {
var arrayOfHTMLOptions = p.getRowActions();
//inserting options to DOM...
var theOptionYouWant = document.getElementById('1');
theOptionYouWant.disabled = true;
}
Another option (that might be more elegant depending on the potential upcoming use cases that could require a new change on this function) is to override the method of object "p" through inheritance and build your own p.getRowActions returning the options array you want, then you must update the function that receives this array so it can point to the new "p child object", by doing that you will have a more flexible way to keep changing p.getRowActions.
Here's some cool reading on Object Oriented Programming with Javascript:
http://marcelorjava.wordpress.com/2014/06/07/object-oriented-programming-with-java-and-javascript/
Related
I have an array called contactDetails that keeps a list of different contacts points (e.g. phone number, social media handle, etc) of the user. The available contact platforms are predefined in a list. I have a computed value that keeps track of which platforms the user has not added as a contact detail yet. The computed array is used in a select field for the user to choose from when creating a new contact detail.
new Vue({
el: '#app',
data() {
return {
platforms: [
{
text: 'WhatsApp',
value: 1,
},
{
text: 'Call',
value: 2,
},
{
text: 'Email',
value: 3,
},
{
text: 'LinkedIn',
value: 4,
},
{
text: 'TikTok',
value: 5,
},
{
text: 'Twitter',
value: 6,
},
],
contactDetails: [],
},
onAddContactDetails() {
var selectedPlatform = this.platforms.find(obj => {
return obj.value == this.platformId
})
var newContact = {
platform: selectedPlatform.value,
platformName: selectedPlatform.text,
channel: this.channel,
priority: this.contactPriorityId
}
this.contactDetails.push(newContact)
this.updatePriority(newContact, this.contactDetails)
this.platformId = null
this.contactPriorityId = null
this.channel = null
this.platformList = null;
this.isAddContact = false;
},
computed: {
platformList() {
var list = [];
if (this.contactDetails.length == 0) {
return this.platforms;
} else {
list = this.platforms;
for (var i = 0; i < this.contactDetails.length; i++) {
var id = this.contactDetails[i].platform;
for (var j = 0; j < this.platforms.length; j++) {
if (this.platforms[j].value == id) {
list.splice(j, 1)
}
}
}
}
return list;
},
This is how the dropdown looks like before adding a new contact detail.
However, my computed property updates, but instead of refreshing the list, the new list is appended onto the existing options, thus causing duplication.
The original list + the new list of contact details, which is supposed to be (full list - contacts that the user has already added)
I would like to know how to fix this, and if there is a better way of setting the options available left for the user in the dropdown menu. Thanks!
You are mutating this.platforms in the computed property; you should clone it first if you are going to mutate it:
list = this.platforms.slice()
I'm not sure what's causing the duplication though. You are only ever pushing to contactDetails and removing from platforms.
Your computed property can be simplified quite a bit:
computed: {
platformList() {
// Filter platforms
return this.platforms.filter(platform =>
// Include this platform if there is no contact detail using that platform
!this.contactDetails.some(contact =>
contact.platform === platform.value
)
)
}
}
Can I use getter/setters to do a similar task to an observer?
So for example if I assign an instance of a getter/setter to multiple objects, these will all be references, so if either object causes the getter to change the same code would run right?
I have tried the following code:
var obj = {
value: null,
get val() {
return this.value;
},
set val(x) {
console.log('set');
if (this.value !== x) {
console.log('value has been changed, do stuff!');
}
this.value = x;
}
}
var one = {
name: 'object 1',
value: obj /* Reference object */
}
var two = {
name: 'object 2',
value: obj /* Reference object */
}
var three = {
name: 'object 3',
value: obj /* Reference object */
}
Then run one.value.value = 2 which should fire the console log. However I just get 2 output in the console and no console.log.
Edit
Just saw where I was going wrong, I should be doing one.value.val = 2, this is starting to work, hang on.
Edit 2
Not too sure if this will function the way i'm expecting. I'm going to try and breakdown what i'm trying to do.
I have got an array of objects as follows:
var images = [
{ index: 0, object: HTMLElement, src: String, active: Object, alt: String },
{ index: 1, object: HTMLElement, src: String, active: Object, alt: String },
{ index: 2, object: HTMLElement, src: String, active: Object, alt: String },
{ index: 3, object: HTMLElement, src: String, active: Object, alt: String },
{ index: 4, object: HTMLElement, src: String, active: Object, alt: String },
{ index: 5, object: HTMLElement, src: String, active: Object, alt: String },
{ index: 6, object: HTMLElement, src: String, active: Object, alt: String }
];
This object will get duplicated a couple of times throughout my script however the active state needs to remain the same throughout all instances.
How i'm duplicating the object:
var newList = [];
for (var i = 0; i < _.images.length; i++) {
// Create new instances of the images
var img = document.createElement('img');
img.src = images[i].object.src;
img.classList.add('responsive-img');
img.alt = images[i].alt;
var span = document.createElement('span');
span.appendChild(img);
if (i === current) img.parentNode.classList.add('active');
var newImage = {
object: img,
index: i,
src: images[i].src,
active: images[i].active, // Use reference to old list
alt: images[i].alt
};
newList.push(newImage);
// Add each image to the gallery DOM
_.gallery.main.appendChild(span);
}
Basically now what I need to happen, is that if the active value is changed in either reference, then code should execute and add/remove a class from the object within that instance.
Does this make sense?
So if the following is run
images[0].active.val = 1
Then newList[0].object.classList.Add('active'); and images[0].object.classList.Add('active'); executes.
There is more code that should execute however lets take it a step at a time. I was using a Polyfill for Observer before however it's too heavy weight for what i want to do and over the top, also having issues with it on Internet Explorer.
I think the best way to do this is maybe some kind of callback from the setter so I could run unique code for each instance that this object is within?
It feels a bit hackish but adding a getter to active to set the object you are referring should work :
var active = {
_value : null,
object : null,
set value(v) {
_value = v;
this.object.style.display = v;
}
}
var images = [
{img : document.querySelector('.div1'), _active : active, get active () {this._active.object = this.img; return this._active}
},
{img : document.querySelector('.div2'), _active : active, get active () {this._active.object = this.img; return this._active}
}
]
images[0].active.value = 'none';
images[1].active.value = 'block';
<div class = 'div1'>div 1</div>
<div class = 'div2' style = 'display:none'>div 2</div>
I have 2 collections.
ItemList = new Mongo.Collection('items');
BorrowerDetails = new Mongo.Collection('borrow');
ItemList.insert({
brand: "brand-Name",
type: "brand-Type",
._id: id
});
BorrowerDetails.insert({
key: "ItemList.id", //equals to .id of the ItemList Collection
name : "borrowerName"
});
Question !
How can i retrieve records from the BorrowerDetails Collection based on a certain type from the ItemList Collection.
ex. Retrieve all records from the BorrowerDetails Collection where key is equals to the id of a record on the ItemList Collection whose type is equals to "Desktop".
return BorrowerDetails.find(
{ key :
ItemList.find(
{ type : 'Desktop' },
{ fields: {'_id':1 } }
)
}
); //error!
Note that I don't have nodejs right now in my laptop, so might have several errors since I am not able to test it.
First, Create a publication file (eg. server\publications\borrowPub.js). inside the file, you should create a publication method. The logic here is simple, get the itemid array first, and then pass it as parameter in Mongo select $in.
Meteor.publish('queryBorrowerTypeDesktop', function(criteria)
{
var itemArr = ItemList.find( { type : 'Desktop' },
{ fields: {'_id':1 } });
if(itemArr){
//itemArr found, so do a select in using the array of item id we retrieved earlier
var borrowers = BorrowerDetails.find({ key: { $in: itemArr } });
return borrowers;
}else{
//found nothing- so return nothing
return []
}
});
Second, in the router :
Router.route('/test', {
name: 'test',
action: function()
{
//change accordingly.
},
waitOn: function()
{//subscribe from publisher that we just created...
return [
Meteor.subscribe('queryBorrowerTypeDesktop')
];
},
data: function() {
if(Meteor.userId())
{
// also include the sorting and limit so your page will not crash. change accordingly.
return {
borrowerDetails: BorrowerDetails.find({},{sort: {name: -1}, limit: 30}),
}
}
}
});
Note that in data, BorrowerDetails.find() does not need to filter by anything because it has been filtered during the subscribe, which has been cached in MiniMongo in your browser.
This question already has answers here:
Javascript object members that are prototyped as arrays become shared by all class instances
(3 answers)
Closed 7 years ago.
I'm trying to create a builder pattern in JavaScript. But I'm wondering why if I call Object.create twice I got the same list as before.
Here's my code.
var filterBuilder = {
filters: [],
addFilter: function(options) {
var filter = {
'type': 'selector',
'dimension': options.dimension,
'value': options.value
}
this.filters.push(filter);
return this;
},
build: function() {
return this.filters;
}
};
If I run Object.create(filterBuilder).build() I get [] which is good. But when I start adding filter
Object.create(filterBuilder).addFilter({dimension: '1', value: 'v'}).build();
I get one filter which is good
But then if I do
Object.create(filterBuilder).addFilter({dimension: '1', value: 'v'}).addFilter({dimension: '1', value: 'v'}).build();
I will get three filters, the first one is from the previous call. Isn't Object.create supposed to create a new object for me?
Prototype properties are shared, so the filters array is the same for both objects you created. If you want each object to have its own filters you have to add it as an own property (a property that is owned by the object, not the prototype), ie:
var filterBuilder = {
addFilter: function(options) {
var filter = {
'type': 'selector',
'dimension': options.dimension,
'value': options.value
}
this.filters.push(filter);
return this;
},
build: function() {
return this.filters;
}
};
var a = Object.create(filterBuilder)
a.filters = [];
a.addFilter({dimension: '1', value: 'v'}).build();
var b = Object.create(filterBuilder)
b.filters = []
b.addFilter({dimension: '1', value: 'v'}).addFilter({dimension: '1', value: 'v'}).build();
console.log(a.filters.length, b.filters.length); // 1 2
You can do this with new as well:
function FilterContainer() {
this.filters = [];
}
FilterContainer.prototype.addFilter = function() {
...
};
FilterContainer.prototype.build = function() {
...
};
// Has its own `filters` array
new FilterContainer().addFilter(...).build();
When you call Object.create(filterBuilder) several times, you get two objects which hold references to the same filters array.
var b1 = Object.create(filterBuilder);
var b2 = Object.create(filterBuilder);
// now b1.filters is the _same_ object as b2.filters,
// so calling
b1.filters.push(...);
// will inevitably modify b2.filters as well.
Your best choice here is using classical functions and prototypes
function FilterBuilder() {
this.filters = [];
}
FilterBuilder.prototype.addFilter = function() { };
var builder = new FilterBuilder();
builder.addFilter();
Object.create() takes an optional second argument which can define properties that are not inherited from the prototype, so you can (re-)define the filters property of newly created object like this:
Object.create(filterBuilder, {
filters : { writable : true, enumerable: true, value : [] }
})
https://jsfiddle.net/1m7xx4ge/2/
// full code
var filterBuilder = {
filters: [],
addFilter: function(options) {
var filter = {
'type': 'selector',
'dimension': options.dimension,
'value': options.value
}
this.filters.push(filter);
return this;
},
build: function() {
return this.filters;
}
};
Object.create(filterBuilder, {
filters : { writable : true, enumerable : true, value : [] }
})
.addFilter({dimension: '1', value: 'v'}).build();
Object.create(filterBuilder, {
filters : { writable : true, enumerable : true, value : [] }
})
.addFilter({dimension: '1', value: 'v'})
.addFilter({dimension: '1', value: 'v'}).build();
I've got the following JSON provided from a server. With this, I want to create a model with a nested model. I am unsure of which is the way to achieve this.
//json
[{
name : "example",
layout : {
x : 100,
y : 100,
}
}]
I want these to be converted to two nested backbone models with the following structure:
// structure
Image
Layout
...
So I define the Layout model like so:
var Layout = Backbone.Model.extend({});
But which of the two (if any) techniques below should I use to define the Image model? A or B below?
A
var Image = Backbone.Model.extend({
initialize: function() {
this.set({ 'layout' : new Layout(this.get('layout')) })
}
});
or, B
var Image = Backbone.Model.extend({
initialize: function() {
this.layout = new Layout( this.get('layout') );
}
});
I have the very same issue while I'm writing my Backbone application. Having to deal with embedded/nested models. I did some tweaks that I thought was a quite elegant solution.
Yes, you can modify the parse method to change a attributes around in the object, but all of that is actually pretty unmaintainable code IMO, and feels more of a hack than a solution.
Here's what I suggest for your example:
First define your Layout Model like so.
var layoutModel = Backbone.Model.extend({});
Then here's your image Model:
var imageModel = Backbone.Model.extend({
model: {
layout: layoutModel,
},
parse: function(response){
for(var key in this.model)
{
var embeddedClass = this.model[key];
var embeddedData = response[key];
response[key] = new embeddedClass(embeddedData, {parse:true});
}
return response;
}
});
Notice that I have not tampered with the model itself, but merely pass back the desired object from the parse method.
This should ensure the structure of the nested model when you're reading from the server. Now, you would notice that saving or setting is actually not handled here because I feel that it makes sense for you to set the nested model explicitly using the proper model.
Like so:
image.set({layout : new Layout({x: 100, y: 100})})
Also take note that you are actually invoking the parse method in your nested model by calling:
new embeddedClass(embeddedData, {parse:true});
You can define as many nested models in the model field as you need.
Of course, if you want to go as far as saving the nested model in its own table. This wouldn't be sufficient. But in the case of reading and saving the object as a whole, this solution should suffice.
I'm posting this code as an example of Peter Lyon's suggestion to redefine parse. I had the same question and this worked for me (with a Rails backend). This code is written in Coffeescript. I made a few things explicit for people unfamiliar with it.
class AppName.Collections.PostsCollection extends Backbone.Collection
model: AppName.Models.Post
url: '/posts'
...
# parse: redefined to allow for nested models
parse: (response) -> # function definition
# convert each comment attribute into a CommentsCollection
if _.isArray response
_.each response, (obj) ->
obj.comments = new AppName.Collections.CommentsCollection obj.comments
else
response.comments = new AppName.Collections.CommentsCollection response.comments
return response
or, in JS
parse: function(response) {
if (_.isArray(response)) {
return _.each(response, function(obj) {
return obj.comments = new AppName.Collections.CommentsCollection(obj.comments);
});
} else {
response.comments = new AppName.Collections.CommentsCollection(response.comments);
}
return response;
};
Use Backbone.AssociatedModel from Backbone-associations :
var Layout = Backbone.AssociatedModel.extend({
defaults : {
x : 0,
y : 0
}
});
var Image = Backbone.AssociatedModel.extend({
relations : [
type: Backbone.One,
key : 'layout',
relatedModel : Layout
],
defaults : {
name : '',
layout : null
}
});
I'm not sure Backbone itself has a recommended way to do this. Does the Layout object have its own ID and record in the back end database? If so you can make it its own Model as you have. If not, you can just leave it as a nested document, just make sure you convert it to and from JSON properly in the save and parse methods. If you do end up taking an approach like this, I think your A example is more consistent with backbone since set will properly update attributes, but again I'm not sure what Backbone does with nested models by default. It's likely you'll need some custom code to handle this.
I'd go with Option B if you want to keep things simple.
Another good option would be to use Backbone-Relational. You'd just define something like:
var Image = Backbone.Model.extend({
relations: [
{
type: Backbone.HasOne,
key: 'layout',
relatedModel: 'Layout'
}
]
});
I use Backbone DeepModel plugin for nested models and attributes.
https://github.com/powmedia/backbone-deep-model
You can bind to change events 'n levels deep. for example:
model.on('change:example.nestedmodel.attribute', this.myFunction);
CoffeeScript version of rycfung's beautiful answer:
class ImageModel extends Backbone.Model
model: {
layout: LayoutModel
}
parse: (response) =>
for propName,propModel of #model
response[propName] = new propModel( response[propName], {parse:true, parentModel:this} )
return response
Ain't that sweet? ;)
I had the same issue and I've been experimenting with the code in rycfung's answer, which is a great suggestion.
If, however, you do not want to set the nested models directly, or do not want to constantly
pass {parse: true} in the options, another approach would be to redefine set itself.
In Backbone 1.0.0, set is called in constructor, unset, clear, fetch and save.
Consider the following super model, for all models that need to nest models and/or collections.
/** Compound supermodel */
var CompoundModel = Backbone.Model.extend({
/** Override with: key = attribute, value = Model / Collection */
model: {},
/** Override default setter, to create nested models. */
set: function(key, val, options) {
var attrs, prev;
if (key == null) { return this; }
// Handle both `"key", value` and `{key: value}` -style arguments.
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
// Run validation.
if (options) { options.validate = true; }
else { options = { validate: true }; }
// For each `set` attribute, apply the respective nested model.
if (!options.unset) {
for (key in attrs) {
if (key in this.model) {
if (!(attrs[key] instanceof this.model[key])) {
attrs[key] = new this.model[key](attrs[key]);
}
}
}
}
Backbone.Model.prototype.set.call(this, attrs, options);
if (!(attrs = this.changedAttributes())) { return this; }
// Bind new nested models and unbind previous nested models.
for (key in attrs) {
if (key in this.model) {
if (prev = this.previous(key)) {
this._unsetModel(key, prev);
}
if (!options.unset) {
this._setModel(key, attrs[key]);
}
}
}
return this;
},
/** Callback for `set` nested models.
* Receives:
* (String) key: the key on which the model is `set`.
* (Object) model: the `set` nested model.
*/
_setModel: function (key, model) {},
/** Callback for `unset` nested models.
* Receives:
* (String) key: the key on which the model is `unset`.
* (Object) model: the `unset` nested model.
*/
_unsetModel: function (key, model) {}
});
Notice that model, _setModel and _unsetModel are left blank on purpose. At this level of abstraction you probably can't define any reasonable actions for the callbacks. However, you may want to override them in the submodels that extend CompoundModel.
Those callbacks are useful, for instance, to bind listeners and propagate change events.
Example:
var Layout = Backbone.Model.extend({});
var Image = CompoundModel.extend({
defaults: function () {
return {
name: "example",
layout: { x: 0, y: 0 }
};
},
/** We need to override this, to define the nested model. */
model: { layout: Layout },
initialize: function () {
_.bindAll(this, "_propagateChange");
},
/** Callback to propagate "change" events. */
_propagateChange: function () {
this.trigger("change:layout", this, this.get("layout"), null);
this.trigger("change", this, null);
},
/** We override this callback to bind the listener.
* This is called when a Layout is set.
*/
_setModel: function (key, model) {
if (key !== "layout") { return false; }
this.listenTo(model, "change", this._propagateChange);
},
/** We override this callback to unbind the listener.
* This is called when a Layout is unset, or overwritten.
*/
_unsetModel: function (key, model) {
if (key !== "layout") { return false; }
this.stopListening();
}
});
With this, you have automatic nested model creation and event propagation. Sample usage is also provided and tested:
function logStringified (obj) {
console.log(JSON.stringify(obj));
}
// Create an image with the default attributes.
// Note that a Layout model is created too,
// since we have a default value for "layout".
var img = new Image();
logStringified(img);
// Log the image everytime a "change" is fired.
img.on("change", logStringified);
// Creates the nested model with the given attributes.
img.set("layout", { x: 100, y: 100 });
// Writing on the layout propagates "change" to the image.
// This makes the image also fire a "change", because of `_propagateChange`.
img.get("layout").set("x", 50);
// You may also set model instances yourself.
img.set("layout", new Layout({ x: 100, y: 100 }));
Output:
{"name":"example","layout":{"x":0,"y":0}}
{"name":"example","layout":{"x":100,"y":100}}
{"name":"example","layout":{"x":50,"y":100}}
{"name":"example","layout":{"x":100,"y":100}}
I realize I'm late to this party, but we recently released a plugin to deal with exactly this scenario. It's called backbone-nestify.
So your nested model remains unchanged:
var Layout = Backbone.Model.extend({...});
Then use the plugin when defining the containing model (using Underscore.extend):
var spec = {
layout: Layout
};
var Image = Backbone.Model.extend(_.extend({
// ...
}, nestify(spec));
After that, assuming you have a model m which is an instance of Image, and you've set the JSON from the question on m, you can do:
m.get("layout"); //returns the nested instance of Layout
m.get("layout|x"); //returns 100
m.set("layout|x", 50);
m.get("layout|x"); //returns 50
Use backbone-forms
It supports nested forms, models and toJSON. ALL NESTED
var Address = Backbone.Model.extend({
schema: {
street: 'Text'
},
defaults: {
street: "Arteaga"
}
});
var User = Backbone.Model.extend({
schema: {
title: { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
name: 'Text',
email: { validators: ['required', 'email'] },
birthday: 'Date',
password: 'Password',
address: { type: 'NestedModel', model: Address },
notes: { type: 'List', itemType: 'Text' }
},
constructor: function(){
Backbone.Model.apply(this, arguments);
},
defaults: {
email: "x#x.com"
}
});
var user = new User();
user.set({address: {street: "my other street"}});
console.log(user.toJSON()["address"]["street"])
//=> my other street
var form = new Backbone.Form({
model: user
}).render();
$('body').append(form.el);
If you don't want to add yet another framework, you might consider creating a base class with overridden set and toJSON and use it like this:
// Declaration
window.app.viewer.Model.GallerySection = window.app.Model.BaseModel.extend({
nestedTypes: {
background: window.app.viewer.Model.Image,
images: window.app.viewer.Collection.MediaCollection
}
});
// Usage
var gallery = new window.app.viewer.Model.GallerySection({
background: { url: 'http://example.com/example.jpg' },
images: [
{ url: 'http://example.com/1.jpg' },
{ url: 'http://example.com/2.jpg' },
{ url: 'http://example.com/3.jpg' }
],
title: 'Wow'
}); // (fetch will work equally well)
console.log(gallery.get('background')); // window.app.viewer.Model.Image
console.log(gallery.get('images')); // window.app.viewer.Collection.MediaCollection
console.log(gallery.get('title')); // plain string
You'll need BaseModel from this answer (available, if you fancy, as a gist).
We have this problem too and a team worker has implemented a plugin named backbone-nested-attributes.
The usage is very simple. Example:
var Tree = Backbone.Model.extend({
relations: [
{
key: 'fruits',
relatedModel: function () { return Fruit }
}
]
})
var Fruit = Backbone.Model.extend({
})
With this, the Tree model can access then fruits:
tree.get('fruits')
You can see more informations here:
https://github.com/dtmtec/backbone-nested-attributes