NoTemplateError Backbone.Marrionette but show template in error msg - backbone.js

Here is my error:
Uncaught NoTemplateError: Could not find template: '<!-- HTML Template -->
<div id="start_div">
<h2>Choose your path to ... // the rest of the template
It is telling me that there is no template but then it outputs the template that it said it could not find.
Here is my code:
require(["jquery", "marionette", "views/StartView" ],
function($, marionette, StartView) {
var SCApp = new marionette.Application();
SCApp.addRegions({
mainRegion: "#center_court"
});
var startView = new StartView();
SCApp.mainRegion.show(startView);
SCApp.start();
}
Here is the StartView.js
define(["jquery", "marionette", "text!templates/startDiv.html"],
function($, marionette, template){
var StartView = marionette.ItemView.extend({
//template: "#start_div"
template: template
});
// Returns the View class
return StartView;
});
Can anyone see what I'm doing wrong? Do I need something for templating in the require method?
Any suggestion are greatly appreciated.
Andrew

Usually Marionette search for a template inside the DOM with an ID equal to the one you reference in your view, so you have to change the loadTemplate from Marionette.TemplateCache in this way:
Backbone.Marionette.TemplateCache.prototype.loadTemplate = function(templateId) {
var template = templateId;
if (!template || template.length === 0){
var msg = "Could not find template: '" + templateId + "'";
var err = new Error(msg);
err.name = "NoTemplateError";
throw err;
}
return template;
};
I actually don't remember where I found this function, I can't find it anymore in Marionette's Wiki, anyway it's working fine for me.

I had the same issue yesterday and found the next interesting facts:
When I've changed the 'not found' template's content, it wasn't changed in error message.
When I've changed it's file name (and updated it in import statement) — the error was fixed, updated content was shown.
... then I've changed the name back, everything was fine.
Looks like some bug with caching.
Upd: here I found deep analysis and solution:
http://blog.icanmakethiswork.io/2014/03/caching-and-cache-busting-with-requirejs.html

Related

Backbonejs: model not getting passed in underscore template

I am new to backbonejs. What I am trying to do is, render a template on page load and pass model as data parameter in _.template function. Here is my bacbone code:
var Trip = Backbone.Model.extend({
url: '/trips/' + trip_id + '/show'
});
var InviteTraveller = Backbone.View.extend({
el: '.page',
render: function () {
var that = this;
var trip = new Trip();
trip.fetch({
success: function(){
console.log(trip); //logs trip object correctly
var template = _.template($('#invite-traveller-template').html(), {trip: trip});
that.$el.html(template);
}
});
}
});
var Router = Backbone.Router.extend({
routes: {
'': 'fetchTrip'
}
});
var inviteTraveller = new InviteTraveller();
var router = new Router();
router.on('route:fetchTrip',function () {
inviteTraveller.render();
});
Backbone.history.start();
And here is my sample template:
<script type="text/template" id="invite-traveller-template">
<h3>Trip</h3>
<h3><%= trip.get('name') %></h3>
</script>
On running, I am getting the this in browser window and console shows:
trip is not defined
I am facing this issue since yesterday but could not figure out the solution yet. Not understanding what is going wrong, code also seems to be right. Any help would be greatly appreciated.
Update:
I removed
inviteTravellers.render();
from router.on() and then reloaded the page in browser. I still got same error which means that <script></script> (template) is being compiled before calling render() of InviteTraveller view. What can be the possible reason for this?
I had the same issue (underscore v1.8.2). My fix:
var template = _.template($('#invite-traveller-template').html());
var compiled = template({trip: trip});
that.$el.html(compiled);
You're passing the whole model to the template. Typically you would call model.toJSON and then pass its result to the template. Additionally using <%= in your template to render the attribute, which is meant for interpolating variables from that JSON object you're passing.
You can pass a whole model to the template and use <% ... %> to execute pure Javascript code and use print to get the attribute but it's probably overkill.
Have a look at this fiddle.
You code work perfectfly, here's it
I think that your problem came from another code, not the one you have posted, because there's no way for your view to render if you remove :
inviteTravellers.render();
Try to chaneg <h3><% trip.get('name'); %></h3> by <h3><%= trip.get('name') %></h3>
My code seems to be right but still my template was getting compiled on page load and I was getting trip is not defined error. I did not understand the reason of this behavior yet.
I solved this issue by using handlebarsjs instead of default underscore templates.

Uncaught NoElError: An 'el' must be specified for a region

I'm trying to use this code for view animation and calling it BaseView:
https://gist.github.com/brian-mann/3947145
then extending view like this:
define(['underscore',
'handlebars',
'views/BaseView',
'text!templates/components/login.tmpl'
], function (
_,
Handlebars,
BaseView,
loginTemplate
) {
'use strict';
var LoginView, errorMap;
LoginView = BaseView.extend({
compiledTemplate: Handlebars.compile(loginTemplate),
events: {
'submit #loginForm': 'login'
},
initialize : function(options){
this.proxyLoginSuccess = options.loginSuccess;
this.errorMap = options.errorMap;
}...
});
return LoginView;
});
It is giving me this error: Uncaught NoElError: An 'el' must be specified for a region.
I tried to remove this.ensureEl(); but doesn't make any difference. Appreciate any help.
You seem to be unclear about some Marionette concepts. The code you linked isn't a view, it's a Marionette Region, and is therefore used to show views, not to be extended from as in your code. This is how you would use it (e.g.):
myApp.addRegions({
fadeRegion: FadeTransitionRegion.extend({
el: "#some-selector"
})
});
Then, you instantiate a view instance and show it:
var myView = new LoginView({
el: "#another-selector"
});
myApp.fadeRegion.show(myView);
In any case, your view needs to have an el attribute defined, either in the view definition, or when it gets instantiated (as above).
If you're still confused about the attributes and specifying them in the view definition or at run time, I'd suggest you read the free preview to my Marionette book where it's explained in more detail.

Backbone.history.start() issue

I'm trying this easy code from Addy's book but I can't make it work:
var TodoRouter = Backbone.Router.extend({
routes: {
"about" : "showAbout",
"search/:query" : "searchTodos",
"search/:query/p:page" : "searchTodos"
},
showAbout: function(){},
searchTodos: function(query, page){
var page_number = page || 1;
console.log("Page number: " + page_number + " of the results for todos containing the wo");
}
});
var myTodoRouter = new TodoRouter();
Backbone.history.start();
The console returns this with an error:
Uncaught TypeError: Property '$' of object #<Object> is not a function backbone-min.js:1
h.extend.start backbone-min.js:1
(anonymous function)
If I comment out Backbone.history.start() there's no error (neither the "app" behaves the way it is supposed to behave).
Any help is appreciated.
[SOLVED] the JS files (JQuery, Underscore and Backbone were added to HTML in the wrong order. The right order for me was: JQuery, Underscore, Backbone, MyOwnJSFiles. Thanks anyone for reading, hope this helps

Backbone.Marionette CollectionView template 'undefined'

I've been working off of Brian Mann's BackboneRails screencast, so my application structure is totally consistent with those.
The following defines the 'show' portion of a the HomepageApp Marionette Appication.
My.module('HomepageApp.Show', function(Show, App, Backbone, Marionette, $, _){
Show.Photo = Marionette.ItemView.extend({
tagName:'span'
});
Show.Photos = Marionette.CollectionView.extend({
template: 'homepage/show/templates/photos',
itemView:Show.Photo,
itemViewContainer: '#photos'
});
Show.Layout = Marionette.Layout.extend({
template: 'homepage/show/templates/layout',
regions:{
photoRegion: '#photo-region'
}
});
});
I'm also overriding the Marionette.Renderer.render function with the following:
Backbone.Marionette.Renderer.render = function(template, data){
var path = JST["backbone/apps/" + template];
try{
if(!path) throw({message: "Template '" + template + "' not found!"});
return path(data);
}
catch(err){
console.log(err.message);
}
}
All of my views, including many not shown here are working perfectly. The issue is that the 'template' propery of the Show.Photos CollectionView is turning up as 'undefined' in my renderer override giving me the following error:
Template 'undefined' not found!
The odd thing is that this even happens when I pass no value for the template property at all.
I also know that I'm passing it a valid Backbone collection on instantiation.
I'm totally stuck. Anyone familiar with this phenomenon?
A CollectionView is not supposed to have a template, for this purpose you should use CompositeView, as stated in the docs:
A CompositeView extends from CollectionView to be used as a composite
view for scenarios where it should represent both a branch and leaf in
a tree structure, or for scenarios where a collection needs to be
rendered within a wrapper template.
You can read more here: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.compositeview.md

Handlebar compiled html not recognizing template function in backbone.js

The project I am on is currently using Backbone.js to create a website and is using Handlebars (http://handlebarsjs.com/) as the templating system. I am attempting to create a sub-view that gets values from a json document into a corresponding template and then return that to a parent view.
The problem I am running into is that when I use
Handlebars.Compile(referenceViewTemplate)
it then doesn't recognize the template function when I try to replace the tokens using
this.template({ identifier: value })
The template code is:
<div id="reference-template">
<div class="id">{{id}}</div>
<div class="reference">{{content}}</div>
</div>
The backbone model is:
define(['underscore','backbone'],
function(_, Backbone){
var reference = Backbone.Model.extend({
initialize: function(){}
});
return reference;
});
The backbone collection code is:
define(['underscore','backbone','models/reference'],
function(_, Backbone, Reference){
var References = Backbone.Collection.extend({
model: Reference,
parse:function(response){ return response; }
});
return new References;
});
The code in the parent view which calls the reference view is:
this.ref = new ReferenceView();
this.ref.model = this.model.page_refs; //page_refs is the section in the json which has the relevant content
this.ref.render(section); //section is the specific part of the json which should be rendered in the view
And the code in the ReferenceView is:
define([
// These are path alias that we configured in our bootstrap
'jquery','underscore','backbone','handlebars',
'models/reference','collections/references','text!templates/reference.html'],
function($, _, Backbone, Handlebars, Reference, References, referenceViewTemplate) {
var ReferenceView = Backbone.View.extend({
//Define the default template
template: Handlebars.Compiler(referenceViewTemplate),
el: ".overlay-references",
model: new Reference,
events:{},
initialize : function() {
this.model.bind('change', this.render, this);
return this;
},
// Render function
render : function(section) {
//this is where it says "TypeError: this.template is not a function"
$(this.el).append(this.template(References.get(section).get("content")));
return this;
}
});
I know this is a lot to read through and I appreciate anyone taking the time to do so, please let me know if there is anything else I can provide to clarify.
The answer is that apparently I was using the wrong function to compile the html. For some reason I typed in Handlebars.Compiler instead of Handlebars.compile
This hasn't solved all the problems in my project (template is being passed back now, but without the values entered), but at least it's a step forward.

Resources