0

I want to differentiate node items based on item_id with Backbone.xmpp. For example in the todo.app for each "todo" item I want to be able to assign different notes (or several users publish notes on each "todo"). I thought of assigning those notes to a todo based on the todo id.

Can I use Backbone relational with Backbone.xmpp ?

Any help or guidelines are appreciated.

Edit2: What options do I have to store nested models in leaf nodes on the xmpp server?

  1. todos and notes are separate items published on the leaf node. Will it be efficient to assign comments to todos? The differetiation will be based on item ids (todoid: todo_1, noteid: todo_1_note_1).

  2. todos are items and notes are an array of objects inside a todo item (JSON objects)? But with this solution I won't get notifications when notes are published since it will be an update of the todo item. Further, all notes will be stored in one single item - and this could get very long.

  3. Originally I had the idea to map todos on leaf nodes (as leaf node name or "title" attribute) and notes on items, but BB.xmpp would not support this so far right?

Therefore, I tend to the first solution where todos and notes are differentiated by item id.

How is it possible in Backbone.xmpp to achieve that?

Edit1: The code is for the original todo.app with localstorage.

$(function(){

// ------------------- Todo Model ------------------

var Todo = Backbone.RelationalModel.extend({

  relations: [{
     type: Backbone.HasMany,
     key: "children",
     relatedModel: "Todo",
     collectionType: "TodoList",
     reverseRelation: {
         key: "parent",
         includeInJSON: "id"
     } 
  }],

initialize: function() {
  console.log("MODEL: initialize()");
  if (!this.get("order") && this.get ("parent")) {
    this.set( {order: this.get("parent").nextChildIndex() });
  }
},

defaults: function() {
    console.log("MODEL: defaults()");
  return { 
      done: false,
      content: "default content" };
},

nextChildIndex: function() {
    var children = this.get( 'children' );
    return children && children.length || 0;
},

clear: function() {
  this.destroy();
}
});

// ------------------- Todo Collection ------------------

var TodoList = Backbone.Collection.extend({
model: Todo,
// Save all of the todo items under the `"todos"` namespace.
localStorage: new Store("todos-backbone"),

done: function() {
  return this.filter(function(todo){ return todo.get('done'); });
},

});
var Todos = new TodoList;

// ------------------- Todo View ------------------

var TodoView = Backbone.View.extend({
tagName:  "li",

template: _.template($('#item-template').html()),

events: {
  "keypress input.add-child": "addChild",
  "click .check"              : "toggleDone",
  "dblclick label.todo-content" : "edit",
  "click span.todo-destroy"   : "clear",
  "keypress .todo-input"      : "updateOnEnter",
  "blur .todo-input"          : "close"
},

initialize: function() {
    console.log("TODOVIEW: initialize()");
  this.model.bind('change', this.render);
  this.model.bind('destroy', this.remove);

  this.model.bind("update:children", this.renderChild);
  this.model.bind("add:children", this.renderChild);

  this.el = $( this.el );
  this.childViews = {};
},

render: function() {
  console.log("TODOVIEW: render()");
  $(this.el).html(this.template(this.model.toJSON()));
  this.setText();
  this.input = this.$('.todo-input');

  this.el.append("<ul>", {"class": "children"}).append("<input>", { type: "text", "class": "add-child" });

  _.each(this.get("children"), function(child) {
      this.renderChild(child);
  }, this);      
    return this;
},

  addChild: function(text) {
      console.log("TODOVIEW: addChild()");
      if (e.keyCode == 13){
          var text = this.el.find("input.add-child").text();
          var child = new Todo( { parent: this.model, text: text});
      }
  },

  renderChild: function(model){
      console.log("TODOVIEW: renderChild()");
    var childView = new TodoView({ model: model});
    this.childViews[model.cid] = childView;
    this.el.find("ul.children").append(childView.render());
  },

// Remove the item, destroy the model.
clear: function() {
    console.log("TODOVIEW: clear()");
  this.model.set({parent: null});
  this.model.destroy();
  //this.model.clear();
}
});

// ------------------ The Application ------------------------

var AppView = Backbone.View.extend({
el: $("#todoapp"),

statsTemplate: _.template($('#stats-template').html()),

events: {
  "keypress #new-todo":  "createOnEnter",
  "keyup #new-todo":     "showTooltip",
  "click .todo-clear a": "clearCompleted",
  "click .mark-all-done": "toggleAllComplete"
},

initialize: function() {
    console.log("APPVIEW: initialize()");
  _.bindAll(this, 'addOne', 'addAll', 'render', 'toggleAllComplete');

  this.input = this.$("#new-todo");

  Todos.bind('add',     this.addOne);
  Todos.bind('reset',   this.addAll);
  Todos.bind('all',     this.render);

  Todos.fetch();
},

render: function() {

},

addOne: function(todo) {
  var view = new TodoView({model: todo});
  this.$("#todo-list").append(view.render().el);
},

addAll: function() {
  Todos.each(this.addOne);
},

// Generate the attributes for a new Todo item.
newAttributes: function() {
  return {
    content: this.input.val(),
    order:   Todos.nextOrder(),
    done:    false
  };
},

createOnEnter: function(e) {
    console.log("APPVIEW: createOnEnter()");
  if (e.keyCode != 13) return;
  Todos.create( this.newAttributes());
  this.input.val('');
},
});
var App = new AppView;
});
genericatz
  • 433
  • 5
  • 16

1 Answers1

1

There isn't anything in particular stopping you from using Backbone.relational together with Backbone.xmpp, other than getting it work ;)

On the other hand, Backbone.xmpp provides real-time notifications that are not going to be triggered unless you save the todo model again so that it gets republished on your XMPP nodes. Also XMPP (as well as backbone) supports simple containment, and you are really just working around it when you try to build relational data around it.

It might be far simpler to just provide the notes on the todo items, which would save you all the effort from integrating with Backbone.relational.

ggozad
  • 13,105
  • 3
  • 40
  • 49
  • Thanks! I actually want those notes to be published. It is just about getting deeper into backbone.xmpp and backbone. I'll need the same functionality in my app later. But still unsure to use Backbone relational or to use nested models suggested here: http://stackoverflow.com/questions/6353607/backbone-js-structuring-nested-views-and-models . – genericatz Jul 03 '12 at 19:08
  • Would you mind to look over the code I've written so far in the Edit1. It is based on the original todo app but I'll add the xmpp version after I get this one to work. I get "Uncaught TypeError: Object function (obj) { return new wrapper(obj); } has no method 'isObject' " on createOnEnter() function of the Application View. I just want to add notes on todos. Here the Todo model "has many" todo children (based on the todo model) . – genericatz Jul 03 '12 at 19:38
  • It's a bit hard to figure out what's going on, a fiddle would help a lot! – ggozad Jul 04 '12 at 16:18
  • Ok, I figured out what my main question is, it is in the Edit 2. I will create the Fiddle tomorrow though. – genericatz Jul 06 '12 at 20:43
  • What do you mean by simple containment? Storing notes inside the todo items in an array like {todo1:{body: "todo1", notes:[{id: "todo1_note1",body: "note1"}], id:"todo1" } ? Will backbone.xmpp send notifications when I add a note to the array "notes"? – genericatz Jul 08 '12 at 07:54
  • Yes, that is correct. And indeed backbone.xmpp will notify when you save your todo item with the updated notes. – ggozad Jul 08 '12 at 08:39
  • Yey! I've got the relational todo app with comments on localStorage to work. But now I see another problem if I use an array inside a node item to store the notes: if there will be an incredible high amount of notes, then the db record will explode. Say for a forum app with posts (items) and comments (an array inside a single item). Will maybe another approach be better for posts and comments as items published to the leaf node but with different id structures in order to differentiate them when fetching? How would I map that approach to Models and Collections? – genericatz Jul 08 '12 at 12:38
  • Openfire which I'm using now for testing uses the type TEXT for the payload column (http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/database-guide.html#ofPubsubItem), so after 64kb it will be truncated and I don't think it will be enough in all cases for a "thread" and all the "comments" on a thread. I could modify the type of the column to LONGTEXT or MEDIUMTEXT though - do you think it will work fine? – genericatz Jul 08 '12 at 14:12