is there a way to specify a template for marionette region?
right now i'm using the layout object to specify a template.
AppLayout = Backbone.Marionette.Layout.extend({
template: tmpl
});
var layout = new AppLayout();
App.main.show(layout);
App.addRegions({
userInfo: "#userInfo",
mainMenu: "#mainMenu",
content: "#content"
});
App.mainMenu.show(new mainMenuView.Views.menu());
App.content.show(new dashboard.Views.main());
why i cannot get access directly from my app object to my regions, when i define them inside the layout object?
AppLayout = Backbone.Marionette.Layout.extend({
template: tmpl
regions: {
userInfo: "#userInfo",
mainMenu: "#mainMenu",
content: "#content"
}
});
var layout = new AppLayout();
App.main.show(layout);
does not work:
App.mainMenu.show(new mainMenuView.Views.menu());
App.content.show(new dashboard.Views.main());
Thanks
is there a way to specify a template for marionette region?
This is exactly a Layout - a rendered template with regions in the rendered output.
why i cannot get access directly from my app object to my regions, when i define them inside the layout object?
The regions in a layout are scoped to the layout's el, the same as events. Even if you have a region defined as a "#id" selector, it is still scoped to the layout and will not find anything outside of the layout's el.
Also, defining a region on a layout adds the region to the layout, not the application object. If you want the regions defined on the application object, you have to add them to the app object directly.
To access the regions of the layout you put in a region, you can write:
App.main.currentView.mainMenu.show(someView)
App.main.currentView.content.show(anotherView)
Related
I have some code which defines a backbone view being loaded as soon as a web page is loaded. The JavaScript is possibly executed before the DOM is fully loaded. If the dom element which becomes $el is not available when the code that defines the view is run is this a problem?
Programmatically I have something like this:
var view = Backbone.View.extend({
el: jQuery("#test")
events: {
}
render: function() {
this.$el.html();
}
//other view code
});
return view;
//some time passes
//with the view rendered above I now call :
view.render()
the problem is that when the render method is called this.$el is undefined. This is because when the first block of code was executed #test had not been loaded into the DOM. So; when the function Backbone.View.extend is called the 'el' element has to be loaded?
The context of this is a backbone application loaded via AMD. The first block of code is in a module. The module is 'required' before the DOM is loaded. Is this a common problem? How is it normally dealt with?
Thanks
el should not be a jQuery object but only a selector, $el will be the jQuery object for that selector. Also the id you specify as the el has to be found at initialization. So yes, the element has to be in the dom before you make it the el for the view.
If you're not creating / populating the view before making it a Backbone view you could do something like this to have backbone create the html tags etc. for you:
var view = Backbone.View.extend({
tagName: 'div',
id: 'test',
events: {
},
render: function() {
this.$el.html();
},
//other view code
});
You could then use templates to populate the view in your render function.
Short answer: Yes, the view element has to be loaded into the DOM when you initialize the view.
Our application uses Mustache templates in the index.mustache and makes the initial API call with Symfony instead of using Backbone. This is so the user won't be staring at a blank screen on initial page load.
Now how can we use Marionette afterwards to bind to the rendered page elements in the DOM (so we can manipulate the data and add interactivity), instead of passing a new template?
As far as our research suggests, we need to always pass in a template to Marionette Layout and ItemView, or we get a 'no template error'.
Is there an el property we can use, just like in Backbone?
The other option would be to extend Marionette.View, but it is not advised to do so.
You just should instantiate the view, without rendering.
http://jsfiddle.net/vpetrychuk/PkNTp/
var ItemView = Backbone.Marionette.ItemView.extend({
el : '.content',
events : {
'click' : 'clickHandler'
},
clickHandler : function () {
this.$el.append('clickHandler');
}
});
new ItemView();
Say I have these two Backbone.Marionette views:
var FooView = Backbone.Marionette.ItemView.extend({
tagName: p,
id: 'foo',
template: this.templates.summary
});
var BarView = Backbone.Marionette.ItemView.extend({
template: this.templates.summary
});
And then I want to show them inside an app region, like so:
App.contentRegion.show(new FooView/BarView());
The first view would create a new element and append it to the region. I thought the second way would be more like a standard Backbone view and attach itself to the region without creating a new element, but it wraps it in a tag. Is there a way to avoid this without using something like setElement()?
For this, you should use the attachView method: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#call-attachview-on-region
It is pretty basic thing but I still can't find the answer. I need to set View's el: to div which is in underscore.js template.
<script id="product" type="text/template">
<div class="productInfo"></div>
<div class="prices"></div>
<div class="photos"></div>
</script>
The first view renders the product template. I need to render other Views to divs in this template. I don't know how to set el:, because el: '.prices' just don't work with divs in template.
This Views structure is similar to How to handle initializing and rendering subviews in Backbone.js?. But I use template instead of rendering to existing divs.
So the problem is using a CSS selector string for this.el won't find anything if the matching <div> is not attached to the page's DOM. In the case of you <script> tag template, the contents of the <script> tag are not attached DOM nodes, there are just a single text node.
One option given your HTML would be to just forget about the <script> tag and put your empty <div> tags straight into the HTML. They are empty and thus should be harmless and invisible until you actual render some content within them. If you do that, el: '.productInfo:first' should work fine.
Other than that, you'll need to put logic into your parent view along these lines:
Render the template into a detached DOM node
Search that detached DOM node for subview divs
Map the subview div to the corresponding backbone view subclass
instantiate and render the subview, then use something like this.$el.find('.productInfo').replaceWith(productInfoView.el) to put the rendered HTML into the parent view at the right location
My general comment is that views should render to detached DOM nodes and leave it to other components such as the router or layout managers to decide where in the real DOM they get attached. I think this makes the views more reusable and testable.
Render the parent view, then assign the '.prices' as the el of the child:
var ParentView = Backbone.View.extend({
render : function() {
var html='<h1>Parent View</h1><div class="productInfo"></div><div class="prices"></div><div class="photos"></div>';
this.$el.html(html);
var prices = new PricesView({
el : this.$('.prices')
});
prices.render();
}
});
var PricesView = Backbone.View.extend({
render : function() {
var html='<h2>Prices View</h1>';
this.$el.html(html);
}
});
// Create a parent view instance and render it
var parent = new ParentView({
el : $('.parent')
});
parent.render();
Working example on jsfiddle: http://jsfiddle.net/JpeJs/
from version 0.9.9, backbone alaws you to define the el property of a view as a function :
When declaring a View, options, el and tagName may now be defined as functions, if you want their values to be determined at runtime.
Assuming that the subviews are created after the main view, this might help you if your subviews are aware of their parent :
SubView = Backbone.View.extend({
el : function(){
return this.parent.$('.prices');
}
});
var subViewInstance = new SubView({parent : theParentView});
I have a marionette layout, which I want to attach directly to the element of the page.
App.Views.Layouts.Unauthenticated = Backbone.Marionette.Layout.extend
template: "layouts/unauthenticated"
regions:
content: "#content"
header: "#header"
footer: "#footer"
views: {}
initialize:->
#el = $("body")
#delegateEvents()
then later in the app, I do this
App.layouts.unauthenticated = new App.Views.Layouts.Unauthenticated()
App.layouts.unauthenticated.render()
The layout is not attached to the page.
How do I attach it to the body, while I already used body as an "el", since I don't need extra wrappers.
You need to set the el in the definition of the view, not in the initializer.
App.Views.Layouts.Unauthenticated = Backbone.Marionette.Layout.extend
el: "body"
template: "layouts/unauthenticated"
regions: ...