Organize a backbone.js collection? - javascript

How does one create a collection (in backbone.js) that is organized by an id. For example I would think it's quite common that collections need to be organized by date, category, keyword, type the list goes on. In my case I am trying to find an elegant way to organize players to team.
I don't think I need a plugin for this, my goal is just to organize the players to be grouped inside a div while using one clean json file so I can have a nice organized list. Again ideally it would be nice to use one json file for this, and structure the HTML similar to how the json itself is structured in terms of nesting, in my example league being the parent of everything, then team being the parent of the players.
I have gone through many backbone tutorials multiple times, and understand the flow and syntax pretty comfortably, but all tutorials work with one collection outputting a simple list in no specific order.
Basically I want to be able to create a clean json array like below. Then turn it into nice organized HTML.
{
"league":
[{
"team":"Lakers",
"players": [
{
"name": "Kobe"
},
{
"name": "Steve"
}
]
},
{
"team":"Heat",
"players": [
{
"name": "LeBron"
},
{
"name": "Mario"
}
]
}]
}
So this json structure is valid but it's not one I have used it's nested a little bit more, so accessing the models requires a little different technique, I am hoping to learn if this kind of array is ideal? Also if so how would I group say Kobe, Steve inside a div with perhaps the class name Lakers whilst obviously separating it from LeBron and Mario keeping those two inside a div with again perhaps a class of Heat.
Another example I could use would be like a actors to movies collection, again is the json format ideal (seems like it to me) here I obviously group actors to their respected movie? I would greatly appreciate some tips on building a clean view or views with a template or templates for outputting this nice and tidy.
{
"movies":
[{
"title":"Prisoners",
"actors": [
{
"name": "Hugh Jackman"
},
{
"name": "Jake Gyllenhaal"
}
]
},
{
"title":"Elysium",
"actors": [
{
"name": "Matt Damon"
},
{
"name": "Jodie Foster"
}
]
}]
}
Again just working with this json data and backbone.js how do I create a maintainable view for this array?
Final Note: I was able to successfully group players to teams using two json files, and assigning a player and id that matched the team id, then looped the team collection with the player collection inside using where to organize it (I am trying to rethink this better). To me this is not taking advantage of backbone, it can get confusing and just seems wrong to me. So again I hope to improve my knowledge here and get better. I would immensely appreciate clear concise information, I really struggle to wrap my head around this topic :)
THANKS!!

Keep your JSON in a Backbone friendly structure, this will mean your models are easily organised once they are placed into the collection.
JSON example
[
{ league : 1, team : 'lakers', player : 'kobe' }
{ league : 1, team : 'lakers', player : 'steve' }
// And so on
]
Consider that most backbone collections are built via a RESTful JSON api this would be easy to fetch directly into a collection and then sorted. The comparator() function on the collection is run each time a model is added to the collection, or when you ask for it to run.
Backbone collection example
var Players = Backbone.Collection.extend({
initialize : function() {
// Grab the JSON from the API
// this.fetching is now a deferred object
this.fetching = this.fetch();
}
// Comparator example one, as a string
comparator : 'team',
// Comparator example two, as a function
comparator : function(model) {
return model.get('team');
}
});
The comparator as a function approach is obviously better suited to more complex sort algorithms, otherwise the comparator as a string approach would be better. Bear in mind that the function approach, though a string can be returned (such as above), -1 or 1 would be better return values to indicate it's sort position.
Comparator example with model comparison
comparator : function(modelA, modelB) {
var teamA = modelA.get('team'),
playerA = modelA.get('player'),
teamB = modelB.get('team'),
playerB = modelB.get('player');
if (teamA < teamB) { // string comparison
return 1;
} else if (playerA < playerB} {
return 1;
} else {
return -1;
}
}
Now whenever a model is added to the collection it is sorted into it's correct location, if using the last example, by team and then by player name.
Simple view example using the collection
var ViewExample = Backbone.View.extend({
el : "#example-container",
render : function() {
var self = this;
// Use the deffered object to make sure models are
// all available in the collection before we render
this.collection.fetching.done(function() {
self.collection.each(function(model) {
self.$el.append('<p>' + model.get('player') + '</p>');
});
});
return this;
}
});
// Create the view and pass in the collection
// that will immediately fetch it's models
var view = new ViewExample({
collection : new Players()
});
Code here is untested

Start by building a working model of your data. Your JSON suggests a hierarchy : a collection of teams that each have a collection of players. Here's a possible implementation :
var Player = Backbone.Model.extend();
var Players = Backbone.Collection.extend({
model: Player
});
var Team = Backbone.Model.extend({
constructor: function(data, opts) {
// I like my subcollections as attributes of the model
// and not on the settable properties
this.players = new Players();
Backbone.Model.call(this, data, _.extend(opts, {parse: true}));
},
parse: function(data) {
// Players are handled in a subcollection
if (_.isArray(data.players))
this.players.reset(data.players);
// They are removed from the model properties
return _.omit(data, 'players');
}
});
var Teams = Backbone.Collection.extend({
model: Team,
parse: function(resp) {
return resp.league;
}
});
Now you can create your root collection. Note that you could also fetch it instead of instantiating it with the data.
// teams list
var teams = new Teams(data, {parse: true});
// for example, to get all players in all teams
var allplayers = _.flatten(teams.map(function(team) {
return team.players.models;
}));
console.log(_.invoke(allplayers, 'get', 'name'));
And a demo : http://jsfiddle.net/8VpFs/
Once you have your structure in place, you can worry about rendering it. Let's imagine you have this (Underscore) template
<ul>
<% _(teams).each(function(team) { %>
<li><strong><%= team.team %></strong>
<ul>
<% _(team.players).each(function(player) { %>
<li><%= player.name %></li>
<% }); %>
</ul>
</li>
<% }); %>
</ul>
You can alter your Team model to output a serialized representation of you model:
var Team = Backbone.Model.extend({
// ... as before
toJSON: function() {
var json = Backbone.Model.prototype.toJSON.call(this);
json.players = this.players.toJSON();
return json;
}
});
and render your template
var tpl = _.template($('#tpl').html());
var html = tpl({
teams: teams.toJSON()
})
$('body').append(html);
This usually would go into a view.
http://jsfiddle.net/8VpFs/1/
With a fetch
var teams = new Teams();
teams.fetch().then(function() {
var tpl = _.template($('#tpl').html());
var html = tpl({
teams: teams.toJSON()
});
$('body').append(html);
});
http://jsfiddle.net/8VpFs/2/

Related

Accessing items pushed into array

Within my firebase data I have a games object, and a players object. Nested within the players object are unique keys that match the games unique keys, these are the games that include players. Then nested within the game unique keys (inside the players object) are the keys of the actual players who entered that particular game. what I'm trying to accomplish is an ng-repeat of only the games that the current user (player.uid) has joined. So in the code below I'm checking if the players id (inside the players object) matches their firebase UID, and if it does I'm pushing that into empty array, then the loop should iterate over that array and if the keys in the array match the keys in the games object...it returns true; switching the class from 'hideGames', which has a display of none, to 'show games' which has a display of block. This works well if I add the keys to the commented out gamesToShow array, but not in the actual gamesToShow array that should be populated from the loop. What am I doing wrong here? I have tried moving the gamesToshow array but it still logs empty. What do I need to do in order for it to be usable in the for loop? Thanks in advance, I posted relevant code, if any thing else is needed let me know. Thanks everyone.
"games":{
"-JwYx6ckhITt2GWOmzLy":{
"date":"8/27/2015",
"host":"Anthony DeVenuto",
"hostEmail":"anthonydevenuto#gmail.com",
"location":{
"address":"1234 Crooked Rd, Chicago Illl",
"course":"Crooked Stick"
},
"name":"Crooked Stick Run",
"rules":{
"amount":"21",
"format":"Match Play",
"holes":"9",
"perBirdie":"DOES NOT APPLY",
"perSkin":"DOES NOT APPLY",
"time":"12:00pm"
}
},
"-Jwi64w0weox4vxIbz8J":{
"date":"8/23/2015",
"host":"Anthony DeVenuto",
"hostEmail":"anthonydevenuto#gmail.com",
"location":{
"address":"1234 fdsadgad",
"course":"West Hills Gathering"
},
"name":"West Side Shuffle",
"rules":{
"amount":"21",
"format":"Match Play",
"holes":"18",
"perBirdie":"DOES NOT APPLY",
"perSkin":"DOES NOT APPLY",
"time":"1:00pm"
}
},
"-Jwx-f7HnjIKdkMnM16D":{
"date":"8/23/2015",
"host":"Andy",
"hostEmail":"andy#andy.com",
"location":{
"address":"1234 First Ave",
"course":"WestCode Hills"
},
"name":"WestCode Hustle",
"rules":{
"amount":"12",
"format":"Match Play",
"holes":"18",
"perBirdie":"DOES NOT APPLY",
"perSkin":"DOES NOT APPLY",
"time":"1:00pm"
}
}
},
"players":{
"-JwYx6ckhITt2GWOmzLy":{
"-Jx1uw6iY87HoNJfAngF":{
"email":"andy#andy.com",
"id":"simplelogin:19",
"name":"Andy"
}
},
"-Jwi64w0weox4vxIbz8J":{
"-Jx1uxoJ0H8Pycp7V12s":{
"email":"andy#andy.com",
"id":"simplelogin:19",
"name":"Andy"
}
},
"-Jwx-f7HnjIKdkMnM16D":{
"-Jx1nbKxyLcbwFFIGjh4":{
"email":"anthonydevenuto#gmail.com",
"id":"simplelogin:22",
"name":"Anthony DeVenuto"
}
}
},
"users":{ }
}
JS
var player = auth.$getAuth();
$scope.displayGames = function(game){
var gamesToShow = [];
// var gamesToShow = ['-JwYx6ckhITt2GWOmzLy', '-Jwi64w0weox4vxIbz8J'];
var playersRef = fire.child('players');
playersRef.on('value', function(snapshot){
var gamesObjects = snapshot;
gamesObjects.forEach(function(snapshot){
var gameKeys = snapshot.key()
var playerKeys = snapshot;
playerKeys.forEach(function(snapshot){
if (snapshot.val().id == player.uid) {
gamesToShow.push(gameKeys);
console.log(gameKeys)
}
});
});
});
for (var i=0;i<gamesToShow.length;i++) {
var uniqueKeys = gamesToShow[i];
if (game.$id == uniqueKeys) {
return true;
}
};
}
HTML template:
<h1>Dashboard</h1>
<ul>
<li class="hideGames" ng-repeat="game in games" ng-class="{showGames:displayGames(game)}">
Course: {{ game.name }} <br> Date:{{ game.date }}<br>
Remove
</li>
</ul>
If I parse correctly, you are trying to get a list of the games that the current user is playing in. If so, this code will do the trick:
var uid = 'simplelogin:19';
var gamesToShow = [];
ref.child('players').on('value', function(gamesSnapshot) {
gamesSnapshot.forEach(function(gameSnapshot) {
var playerKeys = Object.keys(gameSnapshot.val());
playerKeys.forEach(function(playerKey) {
var player = gameSnapshot.val()[playerKey];
if (player.id === uid) {
console.log(gameSnapshot.key());
gamesToShow.push(gameSnapshot.val());
}
});
});
console.log(gamesToShow);
});
A JSBin that shows this code working: http://jsbin.com/selisa/edit?js,console
But not that your data structure is pretty bad for the goal you're trying to accomplish. You're looping through the players to match them by their key and that makes things complex. Since players have an existing natural key (their uid) and each player can probably join each game only once, you're better off storing the players in a game under their uid:
{
"-JwYx6ckhITt2GWOmzLy": {
"simplelogin:19": true
},
"-Jwi64w0weox4vxIbz8J": {
"simplelogin:19": true
},
"-Jwx-f7HnjIKdkMnM16D": {
"simplelogin:22": true
}
}
With this data structure, you can simply get the list of games with a Firebase query:
ref.child('players')
.orderByChild('simplelogin:19')
.equalTo(true)
.once('value', function(snapshot) {
console.log(snapshot.val());
});
As is quite often the case, you can prevent many headaches by optimizing your data structure for how you intend to use it.
Yet another alternative you may want to consider is to store the games for each player/user under their /users node. That way you wouldn't even need a query, but you could directly access the games with:
ref.child('users').child('simplelogin:19').child('games').once('value', ...
That's going to be the best-performing solution, since it doesn't even require a query to access the games.

Efficient Marionette sorted CollectionView for multiple attributes

I am trying to find a way to efficiently display a sorted Marionette.CollectionView, sorted by multiple attributes without modifying the underlying Backbone collection. For this example, I am using 'name' and 'online' attributes, and want my CollectionView to be displayed in 2 parts:
online, alphabetically
offline, alphabetically
I have a single Collection of Backbone.Models and want to use this across my web application. So having a sort function on my Collection doesn't feel right to me.
My example code is as follows:
var MyCollection = Backbone.Collection.extend({
model:Backbone.Model
});
var myCollection = new MyCollection();
myCollection.set([
{ name : 'Freddy', online : true },
{ name : 'Zorro', online : false },
{ name : 'Charlie', online : false },
{ name : 'Alice', online : true }
]);
var MyView = ...
/*
omitted for brevity, though my template is like
<li>{{name}} {{#if online}}(Online){{/if}}</li>
*/
var MyCollectionView = Marionette.Collection.extend({
childView:MyView,
viewComparator: function (item1, item2) {
var item1Online = item1.get('online');
var item2Online = item2.get('online');
if (item1Online != item2Online)
return item1Online ? -1 : 1;
var item1Name = item1.get('name');
var item2Name = item2.get('name');
return item1Name.localeCompare(item2Name);
}
});
var myCollectionView = new MyCollectionView({collection:myCollection});
appView.getRegion('example').show(myCollectionView);
I would like this to be displayed as:
Alice (Online)
Freddy (Online)
Charlie
Zorro
This is fine when all of the data is added to the collection at once, or add/remove events but if one of the attributes is updated on a model that is already in the collection, the view does not update.
If Charlie's 'online' property changed to true - e.g by performing.
charlieModel.set('online', true)
I would like the CollectionView to have rendered automatically as:
Alice (Online)
Charlie (Online)
Freddy (Online)
Zorro
Any suggestions? Many thanks in advance.
From the backbone documentation
Collections with a comparator will not automatically re-sort if you later change model attributes, so you may wish to call sort after changing model attributes that would affect the order.
You can put somewhere convenient in your code a listener on a change in the model attributes your are targeting that will trigger a re-sort of your collection.
// for example in your collection
initialize: function() {
this.on('change:name', function() { this.sort() }, this);
}
The Marionette team advised having a separate Backbone collection behind the scenes, rather than using the viewComparator on the CollectionView.
Using reorderOnSort on the CollectionView made a huge difference (at least 10x speed up) in terms of render speed.
This option is useful when you have performance issues when you resort your CollectionView.
Without this option, your CollectionView will be completely re-rendered, which can be
costly if you have a large number of elements or if your ChildViews are complex. If this option
is activated, when you sort your Collection, there will be no re-rendering, only the DOM nodes
will be reordered.
My final example code:
var MyView = Backbone.Marionette.ItemView.extend({
modelEvents:{
'change:name change:online': 'render'
},
template:template
});
var MyCollection = Backbone.Collection.extend({
initialize : function(){
this.on('change:name change:online', this.sort, this);
},
comparator : function(item1, item2){
var item1online = item1.get('online');
var item2online = item2.get('online');
if (item1online != item2online)
return item1online ? -1 : 1;
return item1.get('name').localeCompare(item2.get('name'));
}
});
var myCollection = new MyCollection();
var MyCollectionView = Marionette.CollectionView.extend({
childView : MyView,
reorderOnSort : true
});
var myCollectionView = new MyCollectionView({
collection : myCollection
});
appView.region('example').show(myCollectionView);

how to encode this data to parent / children structure in JSON

I am working with d3.js to visualise families of animals (organisms) (up to 4000 at a time) as a tree graph, though the data source could just as well be a directory listing, or list of namespaced objects. my data looks like:
json = {
organisms:[
{name: 'Hemiptera.Miridae.Kanakamiris'},
{name: 'Hemiptera.Miridae.Neophloeobia.incisa'},
{name: 'Lepidoptera.Nymphalidae.Ephinephile.rawnsleyi'},
... etc ...
]
}
my question is: I am trying to find the best way to convert the above data to the hierarchical parent / children data structure as is used by a number of the d3 visualisations such as treemap (for data example see flare.json in the d3/examples/data/ directory).
Here is an example of the desired data structure:
{"name": "ROOT",
"children": [
{"name": "Hemiptera",
"children": [
{"name": "Miridae",
"children": [
{"name": "Kanakamiris", "children":[]},
{"name": "Neophloeobia",
"children": [
{"name": "incisa", "children":[] }
]}
]}
]},
{"name": "Lepidoptera",
"children": [
{"name": "Nymphalidae",
"children": [
{"name": "Ephinephile",
"children": [
{"name": "rawnsleyi", "children":[] }
]}
]}
]}
]}
}
EDIT: enclosed all the original desired data structure inside a ROOT node, so as to conform with the structure of the d3 examples, which have only one master parent node.
I am looking to understand a general design pattern, and as a bonus I would love to see some solutions in either javascript, php, (or even python). javascript is my preference.
In regards to php: the data I am actually using comes from a call to a database by a php script that encodes the results as json.
database results in the php script is an ordered array (see below) if that is any use for php based answers.
Array
(
[0] => Array
(
['Rank_Order'] => 'Hemiptera'
['Rank_Family'] => 'Miridae'
['Rank_Genus'] => 'Kanakamiris'
['Rank_Species'] => ''
) ........
where:
'Rank_Order' isParentOf 'Rank_Family' isParentOf 'Rank_Genus' isParentOf 'Rank_Species'
I asked a similar question focussed on a php solution here, but the only answer is not working on my server, and I dont quite understand what is going on, so I want to ask this question from a design pattern perspective, and to include reference to my actual use which is in javascript and d3.js.
The following is specific to the structure you've provided, it could be made more generic fairly easily. I'm sure the addChild function can be simplified. Hopefully the comments are helpful.
function toHeirarchy(obj) {
// Get the organisms array
var orgName, orgNames = obj.organisms;
// Make root object
var root = {name:'ROOT', children:[]};
// For each organism, get the name parts
for (var i=0, iLen=orgNames.length; i<iLen; i++) {
orgName = orgNames[i].name.split('.');
// Start from root.children
children = root.children;
// For each part of name, get child if already have it
// or add new object and child if not
for (var j=0, jLen=orgName.length; j<jLen; j++) {
children = addChild(children, orgName[j]);
}
}
return root;
// Helper function, iterates over children looking for
// name. If found, returns its child array, otherwise adds a new
// child object and child array and returns it.
function addChild(children, name) {
// Look for name in children
for (var i=0, iLen=children.length; i<iLen; i++) {
// If find name, return its child array
if (children[i].name == name) {
return children[i].children;
}
}
// If didn't find name, add a new object and
// return its child array
children.push({'name': name, 'children':[]});
return children[children.length - 1].children;
}
}
Given your starting input I believe something like the following code will produce your desired output. I don't imagine this is the prettiest way to do it, but it's what came to mind at the time.
It seemed easiest to pre-process the data to first split up the initial array of strings into an array of arrays like this:
[
["Hemiptera","Miridae","Kanakamiris" ],
["Hemiptera","Miridae","Neophloeobia","incisa" ],
//etc
]
...and then process that to get a working object in a form something like this:
working = {
Hemiptera : {
Miridae : {
Kanakamiris : {},
Neophloeobia : {
incisa : {}
}
}
},
Lepidoptera : {
Nymphalidae : {
Ephinephile : {
rawnsleyi : {}
}
}
}
}
...because working with objects rather than arrays makes it easier to test whether child items already exist. Having created the above structure I then process it one last time to get your final desired output. So:
// start by remapping the data to an array of arrays
var organisms = data.organisms.map(function(v) {
return v.name.split(".");
});
// this function recursively processes the above array of arrays
// to create an object whose properties are also objects
function addToHeirarchy(val, level, heirarchy) {
if (val[level]) {
if (!heirarchy.hasOwnProperty(val[level]))
heirarchy[val[level]] = {};
addToHeirarchy(val, level + 1, heirarchy[val[level]]);
}
}
var working = {};
for (var i = 0; i < organisms.length; i++)
addToHeirarchy(organisms[i], 0, working);
// this function recursively processes the object created above
// to create the desired final structure
function remapHeirarchy(item) {
var children = [];
for (var k in item) {
children.push({
"name" : k,
"children" : remapHeirarchy(item[k])
});
}
return children;
}
var heirarchy = {
"name" : "ROOT",
"children" : remapHeirarchy(working)
};
Demo: http://jsfiddle.net/a669F/1/
An alternative answer to my own question....In the past day I have learn't a great deal more about d3.js and in relation to this question d3.nest() with .key() and .entries() is my friend (all d3 functions).
This answer involves changing the initial data, so it may not qualify as a good answer to the specific question i asked. However if someone has a similar question and can change things on the server then this is a pretty simple solution:
return the data from the database in this format:
json = {'Organisms': [
{ 'Rank_Order': 'Hemiptera',
'Rank_Family': 'Miridae',
'Rank_Genus': 'Kanakamiris',
'Rank_Species': '' },
{}, ...
]}
Then using d3.nest()
organismNest = d3.nest()
.key(function(d){return d.Rank_Order;})
.key(function(d){return d.Rank_Family;})
.key(function(d){return d.Rank_Genus;})
.key(function(d){return d.Rank_Species;})
.entries(json.Organism);
this returns:
{
key: "Hemiptera"
values: [
{
key: "Cicadidae"
values: [
{
key: "Pauropsalta "
values: [
{
key: "siccanus"
values: [
Rank_Family: "Cicadidae"
Rank_Genus: "Pauropsalta "
Rank_Order: "Hemiptera"
Rank_Species: "siccanus"
AnotherOriginalDataKey: "original data value"
etc etc, nested and lovely
This returns something very much similar to they array that I described as my desired format above in the question, with a few differences. In particular, There is no all enclosing ROOT element and also whereas they keys I originally wanted were "name" and "children" .nest() returns keys as "key" and "values" respectively.
These alternatives keys are easy enough to use in d3.js by just defining appropriate data accessor functions (basic d3 concept) ... but that is getting beyond the original scope of the question ... hope that helps someone too

Accessing child stories from parent record

I am building a rallygrid to display parent level stories. For each row, I want to iterate all the children of that story and pull some information from each child story. e.g.
Ext.Array.each(data, function(record) {
//Perform custom actions with the data here
//Calculations, etc.
recName=record.get('Name');
if (recName.search(/\[Parent\]/i) != -1) {
// Grab Child Iterations
if (record.get('Children').length) {
var childlist = record.get('Children');
for (var child in childlist) {
// I want to get each child's Iteration !!!
}
} else {
childIter = "none";
}
records.push({
FormattedID: record.get('FormattedID'),
ScheduleState: record.get('ScheduleState'),
Name: recName,
NumChildren: record.get('Children').length,
PRDNumber: record.get('PRDNumber')
});
}
});
But, the record.get('Children') retuns objects that look like:
_rallyAPIMajor "1"
_rallyAPIMinor "34"
_ref "https://rally1.rallydev.com/slm/webservice/1.34/hierarchicalrequirement/7272142216.js"
_refObjectName "[Comp] User Story"
_type "HierarchicalRequirement"
I'm assuming there's some Ext call that will take the _ref URI, download it and parse out the JSON into a nice object I can start doing childrecord.get('field') on, but for the life of me, I can't find the right function to call.
You can use the load method of the record's model to retrieve a specific item as mentioned in this question/answer:
Rally App2.0 - Retrieve a specific story
In your case you can get the model from the existing record:
var model = record.self;
model.load(child.get('ObjectID'), {
//options
});
However in your case if you're just looking for some info on each child story's iteration you can probably just include it in the fetch of your initial WsapiDataStore used to load the parent:
fetch: ['Children', 'Iteration', 'StartDate', 'EndDate']

backbone.js complex model

I am building a web app using backbone.js as an MVC framework. I am struggling in designing my models. I have one parent/main object but it is quite complex/nested in nature i.e over 50 attributes and some nesting going on. What i am struggling with is:
I have something like:
{section1:{
key1:"value1",
key1:"value2"},
section2:{
key1:"value1",
key1:"value2"}
}
Should i flatten the object out like:
{section1_key1:"value1",
section1_key2:"value2",
section2_key1:"value1",
section2_key2:"value2"
}
or should I:
use the backbone-nested plug-in and pass in the large nested JSON object as is?
or create separate models for each section and nest somehow within the parent
model.
or simply create models for the child objects and not worry about the nesting and add some type of reference
Suggestions appreciated.
I'm struggling on this right now as well.
I'm leaning towards option 2.
I have each of the nested sections built out into separate models, and creating an interface similar to SQLObject in Python (or really any ORM)
So given a simple blog post idea:
var Tag = Backbone.Model.extend({
defaults: {
name: ''
},
validate: function(atts){
if(!atts.name || atts.name.length < 2){
return "You must provide a name that's longer than 2 characters";
}
}
});
var TagList = Backbone.Collection.extend({
model: Tag
})
var Entry = Backbone.Model.extend({
defaults: {
author: "Todd",
pub_date: new Date(),
content: "",
title: "",
tags: new TagList()
},
add_tag: function(tag){
var tag_collection = this.get('tags');
tag_collection.add({name: tag});
this.set({tags: tag_collection});
},
remove_tag: function(tag){
tag.destroy();
},
tags: function(){
return this.get('tags').models;
}
});
An alternate idea would to let initialize handle the de-nesting and creation and adding of items to the collection that is then stored as a property on that model.

Categories