I'll start with a clear question and explain on after :
How to properly encapsulate a model, contained in a CompositeView
, into an ItemView
My problem is simple, but I can't manage to get something good working.
I have a tree of Notes.
Each note is a Backbone.model and has a @descendants
collection,
I then have a Backbone.Collection to represent that tree (of which @descendants is an instance)
I setup a basic CollectionView
, with, as an itemView
, the CompositeView
. Everything rendered perfectly and I was quite happy about it. This working solution is shown in the first snippet of code!
Here comes the problem. Building on this, I kinda ran into this issue : Events fired for whole hierarchy which make sense for how my events where bound. At first, I simply added unique selectors (added data-guid to my html elements so I could get them by it) and it worked alright, although it was already getting "hacky". But other similar problem have risen so I decided I needed a solution for this. So, I told myslef, let's encapsulate each model in an ItemView and use the Composite view to recursively render them. But... This has not been for the best in all worlds...
Here is what I had in the beginning :
class Note.ModelView extends Marionette.CompositeView
template: "note/noteModel"
id: "note-item"
itemViewContainer: ".note-descendants"
ui:
noteContent: ".noteContent"
events:
"keypress .noteContent": "createNote"
"click .destroy": "deleteNote"
# ...
initialize: ->
@collection = @model.descendants
# ...
class Note.CollectionView extends Marionette.CollectionView
id: "note-list"
itemView: Note.ModelView
initialize: ->
@listenTo @collection, "sort", @render
Now I transferred every thing that belongs to rendering the Model in a new ItemView
class Note.ModelView extends Marionette.ItemView
template: "note/noteModel"
ui:
noteContent: ".noteContent"
events: ->
guid = @model.get 'guid'
events = {}
events["keypress #noteContent#{guid}"] = "createNote"
events["blur #noteContent#{guid}"] = "updateNote"
events["click #destroy#{guid}"] = @triggerEvent 'deleteNote'
initialize: ->
@bindKeyboardShortcuts()
@listenTo @model, "change:created_at", @setCursor
class Note.TreeView extends Marionette.CompositeView
template: "note/parentNote"
itemView: Note.ModelView
initialize: ->
@collection = @model.descendants
@listenTo @collection, "sort", @render
_.bindAll @, "renderItem"
renderItem: (model) ->
if model.get('parent_id') is 'root'
itemView = new Note.ModelView model: model
itemView.render()
@$el.append itemView.el
onRender: ->
@collection.each this.renderItem
@renderItem @model
appendHtml: (collectionView, itemView) ->
@model.descendants.each (note) =>
iv = new Note.ModelView model: note
iv.render()
@.$('.note-descendants').append iv.el
class Note.CollectionView extends Marionette.CollectionView
id: "note-list"
itemView: Note.TreeView
initialize: ->
@listenTo @collection, "sort", @render
and the noteMode template (parentNote is just an empty template right now)
<button class="btn btn-danger btn-xs untab">UN</button>
<button class="btn btn-success btn-xs tab">TAB</button>
<div class="noteContent">{{{indent}}}{{{title}}}</div>
<button class="destroy"></button>
<div class="note-descendants"></div> # That is where I'm putting the children notes
So this is almost working. But it's hacky and.. well it still doesn't quite work. I've been reading through all documentations, and I've read those two links Derick Bailey on nested structure and CompositeView and David Sulc on Nested Views but I still feel I'm missing some important details.
What I'm looking for, as an answer, is any hint or any common way to manage this with Marionette. I'm really looking for something clean since this is going to be one of the angular piece on which the app will be built.
Maybe also I'm searching in the wrong place? Anything will be welcome!! Thank you very much
I wish you all a very nice night. Thank you for your time.