I am trying to get a final layout like...
Left Column (collectionView)
PanelLayout(LayoutView)
BannerView (ItemView)
ContentView (LayoutView)
Section1 (CompositeView)
gridRow (ItemView)
PanelLayout(LayoutView)
BannerView (ItemView)
ContentView (LayoutView)
Section1 (CompositeView)
gridRow (ItemView)
but my Left Column (collectionView) does not want to show the panelLayout(LayoutView). Is it possible to have a childView: that is a LayoutView (like the example below) and not a ItemView (http://marionettejs.com/docs/v2.4.2/marionette.collectionview.html#collectionviews-childview)
class panelLayoutView extends Marionette.LayoutView
template: Templates['panel']
regions:{
bannerRegion: "#banner-region"
contentRegion: "#content-region"
}
class leftColumnCollectionView extends Marionette.CollectionView
className: "leftColumn column"
childView: panelLayoutView
childViewContainer: "leftColumn"
Yes. There is absolutely nothing wrong with using a LayoutView or any other Marionette view type as the childView for a CollectionView.
Related
I'm trying to follow a Backbone Rails tutorial and I'm getting stuck trying to render my collection of links in a CompositeView, no nesting involved. I suspect that tutorial is drastically outdated, but since I yet lack Backbone skills I can't pin point the problem. Please, take a look at the following code:
Creating a collection of navigational links.
#TestApp.module "Entities", (Entities, App, Backbone, Marionette, $, _) ->
class Entities.Navigation extends Backbone.Model
class Entities.NavigationCollection extends Backbone.Collection
model: Entities.Navigation
API =
getLinks: ->
new Entities.NavigationCollection [
{ name: "one" }
{ name: "two" }
{ name: "three" }
{ name: "four" }
{ name: "five" }
]
App.reqres.setHandler "navigation:entities", ->
API.getLinks()
Core navigation file.
#TestApp.module "NavigationUnit", (NavigationUnit, App, Backbone, Marionette, $, _) ->
#startWithParent = false
API =
listNavigation: ->
NavigationUnit.List.Controller.listNavigation()
NavigationUnit.on "start", ->
API.listNavigation()
Controller, where I'm passing collection to the view.
#TestApp.module "NavigationUnit.List", (List, App, Backbone, Marionette, $, _) ->
List.Controller =
listNavigation: ->
links = App.request "navigation:entities"
navigationView = #getNavigationView links
App.navRegion.show navigationView
getNavigationView: (links) ->
new List.Navigation
collection: links
And the view.
#TestApp.module "NavigationUnit.List", (List, App, Backbone, Marionette, $, _) ->
class List.NavigationLinks extends Marionette.ItemView
template: "navigation/list/templates/_links"
tagName: "li"
class List.Navigation extends Marionette.CompositeView
template: "navigation/list/templates/list_navigation"
itemView: List.NavigationLinks
itemViewContainer: "ul"
Content of the ItemView template is %a{:href => "#"}= #name. And in the CompositeView is a basic wrapper structure with the %ul tag. Now what happens is that the CompositeView renders the template as expected, but it does not populate the %ul with the itemView. Instead it creates amount of divs equals to the amount of models in the collection (five in this case) and inserts there entire wrapper templates, so it looks like this:
#navRegion
.div
.navigation-wrapper
.navigation-content
%ul
.div
.navigation-wrapper
// entire template
.div
.navigation-wrapper
// entire template
//etc +3 divs
What am I doing wrong here?
Your tutorial is probably out of date. Marionette renamed the property from itemView to childView in version 2.0.0.
From the docs
Each childView will be rendered using the childView's template. The CompositeView's
template is rendered and the childView's templates are added to this.
var ChildView = Marionette.ItemView.extend({});
var CompView = Marionette.CompositeView.extend({
childView: ChildView
});
I have a composite view which consist of item view. I need to capture the events of item view, what I am trying to capture is specific item view capture as I am rendering a pop up modal on click of button in item view. The Modal needs to contains the details of item for which it is clicked. Whats happening is if I put the event capture in either or item or composite view with query selector of buttons (this button has hidden span of item id) it always selects the first items.
Sounds like it is doing right thing as the item view repetition in composite view is not changing the id of buttons (even if the hidden span has different id).
Quesiton is how do I achieve capturing specific item events with attributes captures.
code below :
ItemView:
var regItemView = Marionette.ItemView.extend({
template: ProgramRegistraionMainItemView,
tagName: 'div',
className : 'accordion_in',
events : {
'click #subbtn' : function () {
var prgid = $('#regid').html();
var rate = $('#rate').html(); MyApp.mainregion.currentView.appcontent.currentView.maincontent.currentView.contentregion1.currentView.prgregmainmodal.show(new ProgramRegistrationModalView({selectedprgid : prgid,rate: rate}));
}
}
});
Composite View
var RegistrationView = Marionette.CompositeView.extend({
itemView : regItemView,
itemViewContainer: "#mainaccordion",
template : ProgramRegistraionMainCollectionView,
initialize : function(programcollection)
{
this.collection = programcollection;
this.model =null;
},
model : this.model,
collection : this.collection,
showAccord : function () {
//console.log("In Accodian show"+$("#mainaccordion").html());
$("#mainaccordion").smk_Accordion({
showIcon: true, // Show the expand/collapse icons.
animation: true, // Expand/collapse sections with slide aniamtion.
closeAble: true, // Closeable section.
slideSpeed: 200, // the speed of slide animation.
closeOther : false
});
}
Aim is to get the program id of the clicked item (rendered through item view).
From your regItemView's event hash, it looks like the issue is with using an html id for the jQuery event handler. id's are supposed to be unique across the whole page but you have repeated it for each ItemView. Change it to a class or an element name (if you've only got one per item view):
var regItemView = Marionette.ItemView.extend({
template: ProgramRegistraionMainItemView,
tagName: 'div',
className : 'accordion_in',
events : {
'click button' : 'showModal'
},
showModal: function () {
// Show modal somehow
// you can access the model in here as this.model
}
});
Marionette sets the event handler context as the item view so you can simple access the model as this.model. This is better than adding data-id tags into your HTML to retrieve the model.
I have a model as defined below
class Colors extends Backbone.Model
name: -> [#get("name")]
value: -> [#get("value")]
Collection as defined below
class #ColorsCollection extends Backbone.Collection
model: Colors
Select tag as define below
%select{name: "colorslist" type: "hidden" value: "" }
Upon an event, I want to dynamically populate the colorslist select options with data fetched from ColorsCollection.
I have been looking into select2 documentation but unable to find any relevant examples.
Basically, you will bind to the reset event and replace the html and start the select2 plugin.
I know the plugin has some internal ways of doing it - but why deal with having to comb through the documentation.
class View extends Backbone.View
initialize: ->
#collection = new ColorsCollection
# Bind to reset event
#listenTo #collection, "reset", #updateSelect
#collection.fetch()
updateSelect: (collection) ->
# Use template engine (eg. Handlebars) to redraw the html
#$el.find('#selection').html tmpl(#collection)
# Start select2
#$el.find('#selection > select').select2()
I have 2 models, implemented via backbone.relational and backbone.localstorage, they're working good.
and I have 2 views, first is a "single item" viewer and the second one is an item view with a render function to view my single item view in the way I want, the problem is events not working, neither in parent view nor in single item view.
I've reimplemented that code in the similar way to show you how it's not working ( code is in coffeescript ) :
log = console.log
class $.Girl extends Backbone.RelationalModel
localStorage: new Backbone.LocalStorage 'gals'
initialize: -> if typeof #get('id') is 'undefined' then #save() else #fetch()
class $.Girls extends Backbone.RelationalModel
localStorage: new Backbone.LocalStorage 'gals'
relations:[{
type: Backbone.HasMany
key: 'gals'
relatedModel: $.Girl
includeInJson: 'id'
}]
initialize: ->
if typeof #get('id') is 'undefined' then #save() else #fetch()
#fetchRelated()
class $.GirlView extends Marionette.ItemView
tagName: 'tr'
template: (data)-> '<td>'+data.name+' -- '+data.age+'<button>Love</button></td>'
initialize: ->
#listenTo #model,'change',#render
events:
'click button': 'sayLove'
sayLove : -> log 'I Love YOU!'
class $.GirlsView extends Marionette.ItemView
template: (data)->
'<table>
<thead><tr><th>My Gals</th></tr></thead>
<tbody></tbody>
<tfoot><tr><td>I Love Them!</td></tr></tfoot>
</table>'
initialize: (options)->
#models = #model.get('gals').models
#list = []
self = #
_.each #models,(girl)-> self.list.push new $.GirlView {model:girl}
events:
'click th': 'hello'
render: ->
#$el.html(#template {})
self = #
_.each #list,(girl)->
girl.delegateEvents()
self.$('tbody').append girl.render().$el
hello: -> log 'hello'
gal1 = new $.Girl {name:'gal1',age:'22',id:'gal-1'}
gal2 = new $.Girl {name:'gal2',age:'19',id:'gal-2'}
gals = new $.Girls {title:'maGals',id:'gals-1',gals:['gal-1','gal-2']}
gv = new $.GirlsView {model:gals}
gv.render()
$('body').append gv.$el.html()
It's kinda hello world for me.
Any idea how can I implement nested itemViews with events working or any other idea for this snippet is appreciated.
Try calling delegateEvents after appending your child views:
self.$('tbody').append girl.render().el
girl.delegateEvents()
// or maybe #delegateEvents()? the context should be the child here
Edit:
Change $('body').append gv.$el.html() to $('body').append #$el.
I can't get ItemView to render my values defined in the testMap. All I want is the 1, 2, 3 to be dynamically inserted in the <ol class='test-list'> tag as <li> so my html would look like
<ol class="test-list">
<li>1</li>
<li>2</li>
<li>3</li>
</ol>
What am I missing?
testMap =
a: '1'
b: '2'
c: '3'
class TestLayout extends Layout
template: require '/test_template'
regions:
body: 'section'
events:
'click #testme': 'test'
test: -> app.vent.trigger 'test'
class TestItemView extends ItemView
template: require '/test-item'
serializeData: -> {testMap}
class TestListView extends CollectionView
tagName: 'ol'
className: 'test-list'
itemView: TestItemView
module.exports = class TestPlugin extends Application
testList: null
initialize: =>
#test = new Collection
app.vent.on 'test', #showTest, #
showTest: ->
app.layout.test.show #layout = new TestLayout
#layout.body.show #testList= new TestListView collection: #test
My Html file named test-item looks like this:
<span class='test'>
<%= #testMap %>
</span>
All my globals are defined in the extended files.
I think the culprit here is that I can't get my collection to bind to my itemView. Therefore, when I call #showTest function I get nothing because my testMap object is not talking to my #test variable. How can I marry the two object?
#layout.body.show #listView = new TestListView collection: #test