This image was generated via code! Check it out here
//Convert the associations into model definitions.
var Location = Backbone.AssociatedModel.extend({
defaults:{
add1:"",
add2:null,
zip:"",
state:""
}
});
var Project = Backbone.AssociatedModel.extend({
relations:[
{
type:Backbone.Many,
key:'locations',
relatedModel:Location
}
],
defaults:{
name:"",
number:0,
locations:[]
}
});
var Department = Backbone.AssociatedModel.extend({
relations:[
{
type:Backbone.Many,
key:'controls',
relatedModel:Project
},
{
type:Backbone.Many,
key:'locations',
relatedModel:Location
}
],
defaults:{
name:'',
locations:[],
number:-1,
controls:[]
}
});
var Dependent = Backbone.AssociatedModel.extend({
validate:function (attr) {
return (attr.sex && attr.sex != "M" && attr.sex != "F") ? "invalid sex value" : undefined;
},
defaults:{
fname:'',
lname:'',
sex:'F', //{F,M}
age:0,
relationship:'S' //Values {C=Child, P=Parents, S=Spouse}
}
});
var Employee = Backbone.AssociatedModel.extend({
relations:[
{
type:Backbone.One,
key:'works_for',
relatedModel:Department
},
{
type:Backbone.Many,
key:'dependents',
relatedModel:Dependent
},
{
type:Backbone.One,
key:'manager',
relatedModel:'Employee'
}
],
validate:function (attr) {
return (attr.sex && attr.sex != "M" && attr.sex != "F") ? "invalid sex value" : undefined;
},
defaults:{
sex:'M', //{F,M}
age:0,
fname:"",
lname:"",
works_for:{},
dependents:[],
manager:null
}
});
emp = new Employee({
fname:"John",
lname:"Smith",
age:21,
sex:"M"
});
child1 = new Dependent({
fname:"Jane",
lname:"Smith",
sex:"F",
relationship:"C"
});
child2 = new Dependent({
fname:"Barbara",
lname:"Ruth",
sex:"F",
relationship:"C"
});
parent1 = new Dependent({
fname:"Edgar",
lname:"Smith",
sex:"M",
relationship:"P"
});
loc1 = new Location({
add1:"P.O Box 3899",
zip:"94404",
state:"CA"
});
loc2 = new Location({
add1:"P.O Box 4899",
zip:"95502",
state:"CA"
});
project1 = new Project({
name:"Project X",
number:"2"
});
project2 = new Project({
name:"Project Y",
number:"2"
});
project2.get("locations").add(loc2);
project1.get("locations").add(loc1);
dept1 = new Department({
name:"R&D",
number:"23"
});
dept1.set({locations:[loc1, loc2]});
dept1.set({controls:[project1, project2]});
emp.set({"dependents":[child1, parent1]});
emp.on('change', function () {
console.log("Fired emp > change...");
//emp.hasChanged() === true;
//emp.hasChanged("works_for") === true;
});
emp.on('change:works_for', function () {
console.log("Fired emp > change:works_for...");
var changed = emp.changedAttributes();
//changed['works_for'].toJSON() equals emp.get("works_for").toJSON()
//emp.previousAttributes()['works_for'].get('name') === "");
//emp.previousAttributes()['works_for'].get('number') === -1;
//emp.previousAttributes()['works_for'].get('locations').length === 0;
//emp.previousAttributes()['works_for'].get('controls').length === 0;
});
emp.set({works_for:dept1});
//Console log
//Fired emp > change:works_for...
//Fired emp > change...
emp.get('works_for').on('change', function () {
console.log("Fired emp.works_for > change...");
//emp.get("works_for").hasChanged() === true;
//emp.get("works_for").previousa-tributes()["name"] === "R&D";
});
emp.get('works_for').on('change:name', function () {
console.log("Fired emp.works_for > change:name...");
});
emp.on('change:works_for.name', function () {
console.log("Fired emp > change:works_for.name...");
//emp.get("works_for").hasChanged() === true;
//emp.hasChanged() === true;
//emp.hasChanged("works_for") === true;
//emp.changedAttributes()['works_for'].toJSON() equals emp.get("works_for").toJSON();
//emp.get("works_for").previous-attributes()["name"] === "R&D";
//emp.get("works_for").previous("name") === "R&D";
});
emp.on('change:works_for', function () {
console.log("Fired emp > change:works_for...");
//emp.hasChanged());
//emp.hasChanged("works_for"));
//emp.changedAttributes()['works_for'].toJSON() equals emp.get("works_for").toJSON();
//emp.previous-attributes().works_for.name === "R&D";
});
emp.on('nested-change', function () {
console.log("Fired emp > nested-change...");
});
emp.get('works_for').set({name:"Marketing"});
//Console log
// @ emp.get('works_for') level
//Fired emp.works_for > change:name
//Fired emp.works_for > change...
//@ emp level
//Fired emp > change:works_for.name...
//Fired emp > change:works_for...
//Fired emp > nested-change...
//The actual set operation
emp.get('works_for').get("locations").at(0).set('zip', 94403);
A simple update like the one above can be listened to at various levels. See the examples below.
//Listen in @ emp.works_for.locations[0]. Should receive regular backbone events
emp.get('works_for').get('locations').at(0).on('change:zip', function () {
console.log("Fired emp.works_for.locations[0] > change:zip...");
});
emp.get('works_for').get('locations').at(0).on('change', function () {
console.log("Fired emp.works_for.locations[0] > change...");
});
//@ emp.get('works_for').get('locations') level
//Fired emp.works_for.locations[0] > change...
//Fired emp.works_for.locations[0].zip > change...
//Listen in @ emp.works_for level
emp.get('works_for').on('change:locations[0].zip', function () {
console.log("Fired emp.works_for > change:locations[0].zip...");
});
emp.get('works_for').on('change:locations[0]', function () {
console.log("Fired emp.works_for > change:locations[0]...");
});
emp.get('works_for').on('change:controls[0].locations[0].zip', function () {
console.log("Fired emp.works_for > change:controls[0].locations[0].zip...");
});
emp.get('works_for').on('change:controls[0].locations[0]', function () {
console.log("Fired emp.works_for > change:controls[0].locations[0]...");
});
emp.get('works_for').on('change:locations[*]', function () {
console.log("Fired emp.works_for > change:locations[*]...");
});
emp.get('works_for').on('change:controls[*].locations[*]', function () {
console.log("Fired emp.works_for > change:controls[*].locations[*]...");
});
emp.get('works_for').on('change:controls[*].locations[*].zip', function () {
console.log("Fired emp.works_for > change:works_for.controls[*].locations[*].zip...");
});
emp.get('works_for').on('nested-change', function () {
if (arguments[0] == "controls[0].locations[0]")
console.log("Fired emp.works_for > nested-change:controls[0].locations[0]...");
if (arguments[0] == "locations[0]")
console.log("Fired emp.works_for > nested-change:locations[0]...");
});
//Console log
//@ emp.get('works_for') level
//Fired emp.works_for > change:controls[0].locations[0]...
//Fired emp.works_for > change:controls[0].locations[0].zip...
//Fired emp.works_for > change:locations[0]...
//Fired emp.works_for > change:locations[0].zip...
//Fired emp.works_for > nested-change:controls[0].locations[0]...
//Fired emp.works_for > nested-change:locations[0]...
//Fired emp.works_for > change:locations[*]...
//Fired emp.works_for > change:controls[*].locations[*]...
//Fired emp.works_for > change:works_for.controls[*].locations[*].zip...
//Listen in @ emp level
emp.on('change:works_for.locations[0].zip', function () {
console.log("Fired emp > change:works_for.locations[0].zip...");
});
emp.on('change:works_for.locations[0]', function () {
console.log("Fired emp > change:works_for.locations[0]...");
});
emp.on('change:works_for.controls[0].locations[0].zip', function () {
console.log("Fired emp > change:works_for.controls[0].locations[0].zip...");
});
emp.on('change:works_for.controls[0].locations[0]', function () {
console.log("Fired emp > change:works_for.controls[0].locations[0]...");
});
emp.on('nested-change', function () {
if (arguments[0] == "works_for.controls[0].locations[0]")
console.log("Fired emp > nested-change:works_for.controls[0].locations[0]...");
if (arguments[0] == "works_for.locations[0]")
console.log("Fired emp > nested-change:works_for.locations[0]...");
});
emp.on('change:works_for.locations[*]', function () {
console.log("Fired emp > change:works_for.locations[*]...");
});
emp.on('change:works_for.controls[*].locations[*]', function () {
console.log("Fired emp > change:works_for.controls[*].locations[*]...");
});
emp.on('change:works_for.controls[*].locations[*].zip', function () {
console.log("Fired emp > change:works_for.controls[*].locations[*].zip...");
});
//@ emp level
//Fired emp > change:works_for.controls[0].locations[0]...
//Fired emp > change:works_for.controls[0].locations[0].zip...
//Fired emp > change:works_for.locations[0]...
//Fired emp > change:works_for.locations[0].zip...
//Fired emp > nested-change:works_for.controls[0].locations[0]...
//Fired emp > nested-change:works_for.locations[0]...
//Fired emp > change:works_for.locations[*]...
//Fired emp > change:works_for.controls[*].locations[*].zip...
//Fired emp > change:works_for.controls[*].locations[*]...
emp.on('add:dependents', function () {
console.log("Fired emp > add:dependents...");
});
emp.on('remove:dependents', function () {
console.log("Fired emp > remove:dependents...");
});
emp.on('reset:dependents', function () {
console.log("Fired emp > reset:dependents...");
});
emp.get('dependents').on('add', function () {
console.log("Fired emp.dependents add...");
});
emp.get('dependents').on('remove', function () {
console.log("Fired emp.dependents remove...");
});
emp.get('dependents').on('reset', function () {
console.log("Fired emp.dependents reset...");
});
emp.get("dependents").add(child2);
emp.get("dependents").remove([child1]);
emp.get("dependents").reset();
//Console log
//Fired emp.dependents add...
//Fired Fired emp.dependents remove...
//Fired emp.dependents reset...
//Fired emp > add:dependents...
//Fired emp > remove:dependents...
//Fired emp > reset:dependents...