How to treat nested collection events in Marionette?
-
24-12-2019 - |
Question
I have an API resource that gives me a list of users
that each have several items
. The hierarchy is like so:
- users
- user
- items
- item
- item
- item
- user
- items
- item
- item
- item
I would like to display the list of users
on a single page, with each user
entry displaying each of its items
on the page as well.
When any one of these items
is clicked, it should set an chosen
attribute that is accessible through the overall users
collection.
I'm having difficulty getting the item
click information to bubble back up. My current implementation is creating a separate items
collection in order to render the view, but then I lose the connection to its original user
model, so I can't notify it when the item
is selected.
My views are structured like so:
class List.Item extends Marionette.ItemView
template: "path/to/template"
events:
"click" : "choose"
choose: (e) ->
# what to do?
class List.User extends Marionette.CompositeView
collection: @collection
template: "path/to/template"
itemView: List.Item
itemViewContainer: "span"
initialize: ->
@collection = new App.Entities.Items(@model.get("items"), parent: @)
events:
"click a" : "toggleChoose"
@include "Chooseable"
class List.Users extends Marionette.CollectionView
itemView: List.User
Is there a better way to structure these collections or views, or is there a way to pass the information from the List.Item
view to the parent List.User
view and then into the users
collection?
EDIT
I have tried backbone-relational, but it didn't seem to quite do what I need. Please correct me if I'm wrong here.
Solution 2
It is actually possible to instantiate the items
collection to reference the parent user
and vice-versa directly in Backbone:
class Entities.User extends Backbone.Model
...
initialize: ->
@items = new Entities.Items @get("items"),
user: @
class Entities.Items extends Backbone.Collection
...
initialize: (models, options) ->
@user = options?.user
So now the List.User
CompositeView can pass this information to the List.Item
ItemView:
class List.User extends Marionette.CompositeView
collection: @collection
...
initialize: ->
@collection = @model.items
With this in place, it is possible to access the user
directly from the ItemView:
class List.Item extends Marionette.ItemView
...
events:
"click" : "choose"
choose: (e) ->
e.preventDefault()
user = @model.collection.user
console.log "user: ", user
And from there it's possible to take any necessary actions on the user
and its collection.
OTHER TIPS
Your List.Item should contain it's current model with all properties at the time when choose is triggered. In this way, you can trigger other events with the List.Item's model values:
choose(e) : ->
trigger("mylistitem:choose", model)
Then listen for the event elsewhere :
itemView.on("itemview:mylistitem:choose", ( childView, model ) -> {
alert(model.get('..whatever..')
}