How do I select DOM elements being created in a Marionette ItemView? - backbone.js

I have an item view that looks like this:
MyView = Marionette.ItemView.extend({
template: "#static-template"
onRender: function() {
console.log($('#static-template').val())
}
});
I want to use jQuery to select the #static-template element, but I am unable to do. How can I select this element with jQuery inside a Marionette.ItemView?

Use this.$el.
In your case, this.$el.attr("value");

Related

Marionette and Backbone. Rendering javascript slider in View

This is the code:
NewEntry_CategoryView = Backbone.Marionette.ItemView.extend({
template: "#NewEntry_Category-template",
tagName: "p",
initialize: function () {
$("#sliderContainer").slider();
}
});
NewEntry_CategoriesView = Backbone.Marionette.CompositeView.extend({
template: "#NewEntry_Categories-template",
tagName: "div",
itemView: NewEntry_CategoryView,
itemViewContainer: '#categoryContainer',
appendHtml: function (collectionView, itemView) {
collectionView.$("#categoryContainer").append(itemView.el);
}
});
Why does the jquery ui slider not render when I show the NewEntry_CategoriesView ?
DOM events/manipulation like slide() won't have any effect on the view object's initialization because there is no such DOM element available yet.
Instead, you need to listen to dom:refresh of the view to manipulate its DOM element.
So, just put the code in onDomRefreshin your ItemView
onDomRefresh: function(){ $('#sliderContainer').slide() };
This above is a direct fix. But there are two more things to improve:
Don't call other div outside of this view when possible. In this case, if #sliderContainer belongs to another view, send an event to allow it slide itself. This is not the job of CategoryView. If it is inside current view, refer it with this.$el.find(".some-div") or better yet ui object.
Your collectionView's appendHtml is unnecessary. Marionette also takes of this common case.

When I define a backbone view does the view element have to be loaded into the DOM?

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.

How to attach Backbone.Marionette view to existing element without creating extra element

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

Display Empty View in Marionette CompositeView

I'm using a Marionette CompositeView to render an html table. Works great! Now I want to display a message when there are no records in the collection. I'm currently using the emptyView property to render this message. However, the message is rendered in the table wrapper and the tables column headers are still visible. Not exactly what I want. Ideally, I would like to hide/remove the table and display the empty records view and then show it when records are added. I'm struggling to find to best approach to handling this. Are there any suggestions out there?
EmptyView = Marionette.ItemView.extend({
template: "#empty-template"
});
SupportMemberView = Marionette.ItemView.extend({
template: "#member-template"
});
SupportTeamView = Marionette.CompositeView.extend({
template: "#support-team-template",
itemView: SupportMemberView,
emptyView: EmptyView,
itemViewContainer: 'tbody'
});
The accepted answer imposes a dependency between the empty view and the template, which does not feel right.
I think an alternative way to do this is to use dynamic templates in the composite view. This is done by overriding the base View getTemplate() method. Thus your composite view would be defined as follows, assuming you have access to the underscore.js library or equivalent to replace the "_.isEmpty()" function:
SupportTeamView = Marionette.CompositeView.extend({
getTemplate: function() {
if (_.isEmpty(this.collection)) {
return "#empty-template"
} else {
return "#support-team-template";
}
itemView: SupportMemberView,
emptyView: EmptyView,
itemViewContainer: 'tbody'
});
One thing that you can do is on your emprty View use the onRender function to hide the table. this function is called after the render function, so you will be able to manipulate the dom to look the way you want.

Backbone.js turning off wrap by div in render

I have model Post and collection Posts. And want to make form with list of all post in <select id="multi" multiple="multiple">. So i have to make a PostView render inside my #multi with just this template:
<option value=""><%= title %></option>
But finally I get it wrapped with div. Is there any solution for not wrapping this template with <div>?
If you don't define an el (or tagName) for the view (in the class or during instantiation) the view will be placed inside a div tag. http://documentcloud.github.com/backbone/#View-el
var PostView = Backbone.View.extend({
tagName: 'option'
});
UPDATE
Starting v0.9.0, Backbone has view.setElement(element) to get this done.
var PostView = Backbone.View.extend({
initialize: function() {
var template = _.template('<option value=""><%= title %></option>');
var html = template({title: 'post'});
this.setElement(html);
}
});
If you don't want to have the view wrap your HTML, you'll have to do a few things:
Replace this.el entirely
Call delegateEvents on the new el
render: function(){
var html = "some foo";
this.el = html;
this.delegateEvents(this.events);
}
Since Backbone generates a div or other tag (based on your tagName setting for the view), you have to replace it entirely. That's easy to do. When you do that, though, you lose your declared events because Backbone uses jQuery's delegate under the hood to wire them up. To re-enable your declared events, call delegateEvents and pass in your events declarations.
The result is that your view.el will be the <option> tag that you want, and nothing more.
In version 0.9.0, Backbone introduced view.setElement(element) to handle this operation.

Resources