Using Marionette.js to populate subviews in backbone.js - backbone.js

How do I populate table rows in a table using marionette.js in backbone.js?

You need 2 types of views (CompositeView for rendering table and tbody and ItemView for rendering table rows).
var TableView = Marionette.CompositeView.extend({
childView: TableRowView,
childViewContainer: "tbody",
template: _.template('<table><thead></thead><tbody></tbody> <tfoot></tfoot></table>')
})
var TableRowView = Marionette.ItemView.extend({
tagName: "tr",
template: _template('<td><%= someProp %></td><td><%= otherProp =></td>')
})
for more info checkout CompositeView docs

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.

How to update data after model fetch in Handlebars template with Backbone and Marionette?

Trying to have a data field in a Handlebars template update after the model that is assigned to the Marionette CompositeView is fetched, but the HTML in the page is not getting updated.
My code looks like this:
Model:
B.Page.Model = Backbone.Model.extend({
url: function () {
return 'my/resource/';
},
});
View:
B.Page.CompositeView = Backbone.Marionette.CompositeView.extend({
template: Handlebars.compile(templates.find('#my-template').html()),
initialize: function(options) {
_.bindAll(this);
this.model.fetch();
},
)};
Template:
<script id="my-template" type="text/x-handlebars-template">
Date: <span id="my-data-field">{{data}}</span>
</script>
I have checked the resource and it does return proper JSON with the data field set. Also, the model is getting passed in to the view.
I suspect that this is due to the render function not getting called after the data is retrieved; however, I would like to get feedback on how it should be done.
What is a good way to do this?
Thanks!
EDIT: This CompositeView does have a Collection that is associated with it (which renders just fine when I trigger the appropriate event). I purposefully left out that part of the code to avoid muddying up the problem.
Your are right, since a CompositeView extends from CollectionView, it only re-renders on collection events by default. To make it re-render on changes on your model, you could do something like this in your CompositeView:
initialize: function(){
this.listenTo(this.model, "change", this.render);
}
All Marionette views have a modelEvents object that is bound to the passed in model. So you could clean the accepted answer up slightly by doing:
template: Handlebars.compile(templates.find('#my-template').html()),
modelEvents: {
'change': 'render'
}
rather than binding manually in initialize.

How to render a backbone collection into two views

I am using twitter bootstrap link. When the user clicks the link a bootstrap modal appears.
Now because of some bootstrap technical difficulties in modal rendering i need to seperate the link and put the modal out the navbar div.
So consider i have two separate div
<div id="linkDiv">
</div>
and
<div id="modalDiv">
</div>
Now i have only one View which makes a call to the server to get the collection
app.View.FriendRequestListView = Backbone.View.extend( {
templateModalLink: _.template($('#link').html()),
templateModal: _.template($('#modal').html()),
tagName: 'div',
initialize: function(){
this.friendRequestCollection = new app.Collection.FriendRequestCollection();
this.friendRequestCollection.bind("reset", this.render, this);
this.friendRequestCollection.fetch();
},
render: function() {
$(this.el).html(this.templateModalLink({
friendRequestCollection: this.friendRequestCollection}));
return $(this.el);
},
});
Than i can render only one div like following
var list = new app.View.FriendRequestListView();
$('#linkDiv').html(list.$el);
My question is , Is it possible to render two templates at the same time and add the two templates to different DIV like for example in my case i want to get update
templateModalLink template to linkDiv and templateModal template to modalDiv with the collection I am getting from the server.
You have to instantiate the collection before app.View.FriendRequestListView(s) and pass app.View.FriendRequestListView(s) the collection:
var friendRequests = new app.Collection.FriendRequestCollection();
friendRequests.fetch(
success: function(collection, response, options) {
var list1 = new app.View.FriendRequestListView({collection: collection});
var list2 = new app.View.FriendRequestListView({collection: collection});
$('#linkDiv').html(list1.$el);
$('#modalDiv').html(list2.$el);
}
);

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.Marionette - Accessing variables in the ItemView template or CompositeView template

Here i want to access a variable or a list of variables which is passed when initalizing a new view from its corresponding template.
Code example
Creating a list view
#Taskit.module "Tasks.List", (List, Taskit, Backbone, Marionette, $, _) ->
class List.NewTask extends Taskit.Views.ItemView
template: JST["backbone/taskit/tasks/tasks/list/_templates/new_task"]
Template for the above list view
<div id="new-task-form">
</div>
Initializing the ItemView
view = new Taskit.Tasks.List.NewTask
project_id: "project_id"
Here my question is how can i access the "project_id" variable from its template.
<%= project_id %> #is not working
In Backbone it can be achieved by
$(#el).html(#template({task: #model, project_id: "project_id"}))
how to do it in Marionette.js?
You can provide your own method to serialize data:
https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.itemview.md#itemview-serializedata
Backbone.Marionette.ItemView.extend({
serializeData: function(){
var data = this.model.toJSON();
data.project_id = this.project_id;
return data;
}
});

Resources