I am trying to learn how to use Marionette with Backbone. I am not sure why I am getting the following error: Uncaught ChildViewContainerMissingError: The specified "childViewContainer" was not found: ul
Here's a fiddle to my code: http://jsfiddle.net/e7L822c8/
Here is my JavaScript:
window.App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '.js-page'
});
App.start();
var TheModel = Backbone.Model.extend({});
var TheCollection = Backbone.Collection.extend({
model: TheModel,
});
var ListView = Backbone.Marionette.CompositeView.extend({
tagName: 'div',
className: 'js-list-container',
template: _.template( '#ListViewTemplate' ),
childViewContainer: 'ul',
childView: ItemView
});
var ItemView = Backbone.Marionette.ItemView.extend({
initialize: function() {
console.log('this.model =',this.model);
console.log(this);
},
tagName: 'li',
className: 'list-item',
template: _.template( '#ItemViewTemplate' )
});
var dataArray = [
{"name":"FirstObject"},{"name":"SecondObject"},{"name":"ThirdObject"}
];
var theCollection = new TheCollection(dataArray);
var listView = new ListView({collection: theCollection});
App.mainRegion.show(listView);
Here is my HTML:
<div class="js-page">
</div>
<script type="text/template" id="ListViewTemplate">
<h3>Here is a list</h3>
<ul class="js-list">
</ul>
</script>
<script type="text/template" id="ItemViewTemplate">
Display List Item here
</script>
There are two problems in the code :
you have to define ItemView before ListView in your js code
the js cant access the template in your code
template: _.template( '#ListViewTemplate' ),
if you replace ListViewTemplate by its content :
template: _.template( "<h3>Here is a list</h3><ul class='js-list'></ul>" ),
it works check the jsfiddle : http://jsfiddle.net/pwassqww/2/
so the problem is with your template definition .
Related
This is my HTML
<div class="productsContainer">
<ul class="nav nav-tabs" role="tablist" id="products">
</ul>
</div>
<script type="text/template" id="productsTemplate">
<li role="presentation" class="active"><a href="#<%= title %>" aria-controls="<%= title %>" role="tab" data-toggle="tab">
<%= title %>
</a></li>
</script>
This is my JS:
var Product = Backbone.Model.extend();
var Products = Backbone.Collection.extend({
model: Product,
url: '/*server url*/'
});
var ProductView = Backbone.View.extend({
initialize:function(options){
console.log(this.el);
return this.render();
},
el:'div.productsContainer ul',
template: _.template( $('#productsTemplate').html() ),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
renderEL: function(item){
var productView = new ProductView({
model: item
});
}
});
var ProductsView = Backbone.View.extend({
el:'div.productsContainer ul',
initialize:function(options){
this.collection = new Products(options.collection);
this.collection.fetch({reset:true, add:true});
this.listenTo( this.collection, 'reset', this.render);
this.listenTo( this.collection, 'add', this.renderProduct);
return this;
},
render:function(){
this.collection.each(function(item){
this.renderProduct(item);
}, this);
return this;
},
renderProduct: function(item){
var productView = new ProductView({
model: item
});
this.$el.append(productView.render().$el);
}
});
var productsView = new ProductsView({});
$("div.productsContainer").append(productsView.render().$el);
When i used in "var ProductView = Backbone.View.extend({})" tagName:'li', script has added each object, but i get 'li''li''/li''/li'....,so i has use el:''ul'....but script rewrites each object in one element 'li'. how i can realization my script, for each object to add a new tag?
You get 'li''li''/li''/li' because ProductView creates 'li' tag automatically (tagName: 'li') and your template contains also 'li' which is appended/inserted into 'li'. Just remove 'li' from the template and keep 'a' only.
If the 'li' should have any class/attribute use 'className' (className:'active') or 'attributes' (attributes: {role: 'presentation'}) while constructing the view (http://backbonejs.org/#View-constructor).
I'm using Marionette with Handlebars templates and I can't get my itemView to render inside a CollectionView.
Here is the CollectionView code:
define( [ 'App', 'marionette', 'handlebars', 'models/Model', 'collections/Collection', 'text!templates/welcome.html'],
function(App, Marionette, Handlebars, Model, Collection, template) {
//ItemView provides some default rendering logic
var ItemView = Marionette.ItemView.extend( {
//Template HTML string
template: Handlebars.compile(template),
//model: new Model(),
// View Event Handlers
events: {
},
initialize: function(o) {
console.log('init itemView');
}
});
return Marionette.CollectionView.extend( {
issues: new Collection(),
itemView: ItemView,
onRender: function() {this.issues.fetch()},
initialize: function(o) { console.log('init collectionView')}
});
});
here is the template
<div class="hero-unit">
<h1>Marionette-Require-Boilerplate Lite</h1>
<p>Lightweight Marionette Boilerplate application to get you off the ground fast.</p>
<p class="muted">
You are viewing this application on
</p>
<br/>
<table>
{{#each items}}
<tr><td>{{title}} - {{number}}</td></tr>
{{/each}}
</table>
<a class="btn btn-primary btn-large" href="https:github.com/BoilerplateMVC/">See more Boilerplates</a>
The only thing I get from this code is that the CollectionView does trigger its initialize method and that the collection is fetched from GitHub.
There are multiple reasons this could not be working, depending on the Marionette version you are using:
For the latest Marionette version, you have to use 'childView' instead of 'itemView'.
The items to display are expected in the property 'collection' not 'issues'.
example:
var IssuesView = Marionette.CollectionView.extend({
childView: IssueView,
onRender: function () {
this.collection.fetch();
},
initialize: function (o) {
console.log('init collectionView');
}
});
new IssuesView({'collection': new Backbone.Collection()});
Now, based on the code you provided, I assume your goal is to display the issues inside 'items', if that is correct, I will suggest to use a 'CompositeView' instead, and then you can provide a 'container' and render the 'issues' inside the items. For example:
var IssueView = Marionette.ItemView.extend({
itemTag: 'tr',
//Template HTML string
template: Handlebars.compile($("#item-template").html()),
//model: new Model(),
// View Event Handlers
events: {
},
initialize: function (o) {
console.log('init itemView');
}
});
var IssuesView = Marionette.CompositeView.extend({
childView: IssueView,
childViewContainer: "#issues",
template: Handlebars.compile($("#some-template").html()),
onRender: function () {
//this.issues.fetch();
},
initialize: function (o) {
console.log('init collectionView');
}
});
Where your templates are:
<script id="item-template" type="text/x-handlebars-template">
<td>
{{title}} - {{number}}
</td>
</script>
<script id="some-template" type="text/x-handlebars-template">
<div class = "hero-unit" >
<h1>Marionette - Require - Boilerplate Lite </h1>
<p>Lightweight Marionette Boilerplate ...</p>
<p class = "muted"> You are viewing this application on </p>
<br/>
<table id="issues">
</table>
</script>
Here is jsfiddle with a working version of this:
http://jsfiddle.net/gvazq82/v5yj6hp4/2/
Your problem is that you're not specifying a collection in your CollectionView. You want to instead do
var collectionView = Marionette.CollectionView.extend({
collection: new issues
...
});
I am wondering how to log the model used in a Backbone.Marionette CompositeView's template?
The <% console.log(model) %> I am using causes an error Uncaught ReferenceError: model is not defined
Is there a way to log the content of the model from the template?
Here is a fiddle to my code: http://jsfiddle.net/16L1hen4/
Here is my Template and JavaScript
Template:
<div id="main"></div>
<script type="text/template" id="tree-template">
<li><%- name %></li>
<% //This console.log fails and I don't know why %>
<% console.log('inside template model =',model) %>
</script>
JavaScript:
var App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '#main'
});
var TreeModel = Backbone.Model.extend({
});
var TreeCollection = Backbone.Collection.extend({
model: TreeModel,
url: 'https://api.mongolab.com/api/1/databases/backbone-tree/collections/tree?apiKey=akey'
});
// Tree branch view
var CompositeView = Backbone.Marionette.CompositeView.extend({
tagName: 'ul',
template: _.template( $('#tree-template').html() )
});
// Tree root view
var CollectionView = Backbone.Marionette.CollectionView.extend({
tagName: 'div',
className: 'js-tree-root',
childView: CompositeView,
});
var treeCollection = new TreeCollection();
treeCollection.fetch().done(function () {
var collectionView = new CollectionView({collection: treeCollection});
App.mainRegion.show(collectionView);
});
Edit: In a regular Backbone.View I can pass the model to the data as a property. Notice in this example that the View's model is passed to the template with a data property which can be logged in the template. This could be useful in the template to test for the existance of properties on the model. I am not sure how to do this using a Marionette CompositeView
var jsonData = {
"color": "red"
};
var TheModel = Backbone.Model.extend({
});
var TheView = Backbone.View.extend({
el: '#main',
tagName: 'ul',
template: _.template( $('#the-template').html() ),
render: function () {
var tmpl = this.template({data: this.model.toJSON()});
this.$el.html( tmpl );
}
});
var theModel = new TheModel(jsonData);
var theView = new TheView({model: theModel});
theView.render();
<div id="main"></div>
<script type="text/template" id="the-template">
<li><%- data.color %></li>
<% //Log the current model that the template uses %>
<% console.log('template model =',data) %>
</script>
This happens to be related to the anwser I posted on your question here : Backbone Marionette Composite View Rendering Template
and is cause by the same issue. model being undefined in the template context.
The data passed to your template is the following:
{_id: Object, name: "Level 1", children: Array[2]}
and model is undefined in this context.
If you want to log/control the data passed to your template you have should use SerializeData in such a way:
var CompositeView = Backbone.Marionette.CompositeView.extend({
tagName: 'ul',
serializeData: function(){
var data = Backbone.Marionette.CompositeView.prototype.serializeData.apply(this, arguments);
console.log(data);
return data;
},
template: _.template( $('#tree-template').html() )
});
I am using backbone with underscore templates, but I'm having problem getting underscore to render the data I pass along to the template. Here's my code:
define([
'jquery',
'underscore',
'backbone',
'models/home/HomeModel',
'text!/app/templates/home/homeTemplate.html'
], function($, _, Backbone,HomeModel,homeTemplate){
var HomeView = Backbone.View.extend({
el: $("#page"),
initialize: function(){
var self = this;
self.model = new HomeModel();
},
render: function(){
var homeTitle = this.model.get('title');
var homeData = {
title: homeTitle
}
var compiledTemplate = _.template( homeTemplate, homeData );
this.$el.html(compiledTemplate);
}
});
return HomeView;
});
In this code, I can get all the way to the var homeData = {} object, which includes the proper title from the model, but when I create the compiledTemplate, I get an error saying title is not defined.
Any ideas what I'm doing wrong here?
From the Underscore.js documentation
var compiled = _.template("hello: <%= name %>");
compiled({name: 'moe'});
=> "hello: moe"
It looks like you are not using the _.template method correctly. It returns a compiled template function that you can call with the data to render:
var compiledTemplate = _.template( homeTemplate, homeData );
this.$el.html( compiledTemplate( homeData ) );
I have the following backbone application:
On the index.html:
<div class='content'></div>
<div class='container'>
<script type="type="text/x-handlebars-template"" id="product-template">
<h2>Products</h2>
<h3>{{ this.title }}</h3>
</script>
</div>
and the main.js:
$(function() {
var Product = Backbone.Model.extend({
defaults: {
title: "Title",
user_id: 0,
description: "Description"
}
});
var ProductView = Backbone.View.extend({
el: ".content",
initialize: function() {
this.render();
},
render: function() {
var source = $('#product-template').html();
var template = Handlebars.compile(source);
var html = template(Product.model);
this.$el.html(html);
}
});
var productView = new ProductView();
});
It's showing the "Products" heading, so the template is rendering but it's not showing the {{this.title }}. Unfortunately, there isn't any errors showing up in the console, either.
try this:
var ProductView = Backbone.View.extend({
el: ".content",
model: new Product,
initialize: function() {
this.render();
},
render: function() {
var source = $('#product-template').html();
var template = Handlebars.compile(source);
var html = template(this.model.toJSON());
this.$el.html(html);
}
});
to print it
{{ title }}