"el" must exist in DOM when use backbone marionette in browserify - javascript

I use the backbone marionette in browserify.
I met a problem about showing view.
I have addRegions and want to show the ItemView.
But the console show error: Uncaught Error: An "el" #tmp_area must exist in DOM.
My HTML file have #tmp_area area.
When I use require.js it doesn't show this problem, but it happened when I change to use browserify.
I don't know what's wrong.
Below is my code.
app.js
var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;
var Marionette = require('backbone.marionette');
var MyView = require('./views/my_view');
var app = new Marionette.Application();
app.addRegions({
tmp_area: "#tmp_area"
});
app.addInitializer(function() {
var myView = new MyView();
app.tmp_area.show(myView);
});
app.on("initialize:after", function() {
if (Backbone.history) {
Backbone.history.start();
}
});
app.start();
my_view.js
var $ = require('jquery');
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var templates = require('../templates/tmp.hbs');
Backbone.$ = $;
module.exports = Marionette.ItemView.extend({
template: templates,
})
Please help me!
I do appreciate it!

I'm pretty sure that this is related to the document ready state. You can just put a script at the bottom of your HTML or wrap an application initialization step into document.ready function.

Related

this.$el.off is not a function

Previously this will work but I've update the underscore and backbone to the latest version, then I got error of
Uncaught TypeError: this.$el.off is not a function
http://jsfiddle.net/mmm770v8/
SearchView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
var template = _.template( $("#search_template").html(), {} );
this.el.html( template );
},
events: {
"click input[type=button]": "doSearch"
},
doSearch: function(){
// Button clicked
console.log(this.el.find('#search_input').val());
}
});
You have several problems:
Your fiddle was using jQuery 1.5.2 which is ancient and used bind/unbind instead of on/off. Backbone expects a more recent version of jQuery which has on and off functions.
You're using this.el where you mean this.$el. this.el is just a plain old DOM node, this.$el is the cached $(this.el).
The var html = _.template(tmpl, data) form of _.template went away in Underscore 1.7.0. You now need a two step process:
var t = _.template(tmpl);
var h = t(data);
so your render should look more like this:
render: function() {
var template = _.template($("#search_template").html());
this.$el.html(template({}));
}
Updated fiddle: http://jsfiddle.net/ambiguous/L5z4agh4/

Rendering reCAPTCHA v2.0 widget within Backbone view

This is my issue, I have an index.html page which loads the reCAPTCHA script explicitly:
<script src="https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit" async defer></script>
I have a template which contains the reCAPTCHA container element (div):
<form id="payment-<%= model.Id %>" class="form" action="" method="POST">
...
<div class="captcha-container"></div> //not being used yet
</form>
And I have a backbone view which injects the template into index.thml:
'use strict';
var Backbone = require('Backbone');
var Validation = require('backbone-validation');
Backbone.Validation = Validation;
Backbone.$ = $;
module.exports = BaseView.extend({
events: {},
formView: null,
initialize: function (options) {
var loadCaptcha = function() {
window.alert('captcha is ready');
};
},
render: function () {
// renders view using my form template
}
});
At this point I'm unable to even trigger the callback function (loadCaptcha), my suspicion is that the issue lies in the load order, the index page is loaded and the "onload=loadCaptcha" event occurs before the backbone view is initialized. I've tried removing the "async" property from the script tag, but no luck. Any ideas of how I can get this to work?
I figured out the solution, by pulling in the recaptcha script directly from the view which renders it. Hope this helps someone in the future.
loadCaptcha: function() {
var self = this;
var getRecaptchaResponse = function(response) {
self.captchaResponse = response;
};
var renderCaptcha = function() {
self.captchaWidgetId = grecaptcha.render('recaptcha-container-' + self.model.get('Id'), {
sitekey : service.settings.recaptchaSiteKey,
callback: getRecaptchaResponse
});
};
window.renderCaptcha = renderCaptcha;
$.getScript('https://www.google.com/recaptcha/api.js?onload=renderCaptcha&render=explicit', function() {});
},
I would put your captch script in a backbone view. Then put it in the render of your main view. Like that it's modular you have a main view and a subview containing the captcha which is loaded when the main view is rendered.

Nodejs: Expecting a function in instanceof check but got undefined

Getting this odd error when using node-webkit, here is a complete example which can recreate it:
index.js:
var jQuery = require('jquery');
var Backbone = require('backbone');
(function($){
var ListView = Backbone.View.extend({
el: $('body'),
initialize: function(){
_.bindAll(this, 'render');
this.render();
},
render: function(){
$(this.el).append("<ul> <li>hello world</li> </ul>");
}
});
var listView = new ListView();
})(jQuery);
index.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./css/main.css" />
</head>
<body>
</body>
<script src="./js/index.js"></script>
</html>
The stack trace:
TypeError: Expecting a function in instanceof check, but got undefined
at _.extend.setElement (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1046:45)
at _.extend._ensureElement (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1108:14)
at Backbone.View (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1000:10)
at new child (C:\SVN\mapthing\branches\mapthing_js\node_modules\backbone\backbone.js:1566:41)
at file:///C:/SVN/mapthing/branches/mapthing_js/js/index.js:18:18
at file:///C:/SVN/mapthing/branches/mapthing_js/js/index.js:19:3
Having trouble seeing where my problem is?
Most solutions seem to point to having to require jquery first, but I have done this...
I'm a relative n00b so I'm expecting ive done something very daft...
This is a hack, so be warned of that, but the error is coming from this method in the backbone lib (node_modules/backbone/backbone.js:1046 from your stacktrace):
setElement: function(element, delegate) {
if (this.$el) this.undelegateEvents();
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
this.el = this.$el[0];
if (delegate !== false) this.delegateEvents();
return this;
},
Most likely you can circumvent this error by explicitly setting jQuery on Backbone, like this:
var jQuery = require('jquery');
var Backbone = require('backbone');
Backbone.$ = jQuery;
That is a totally untested guess, but it should work.

ReferenceError when trying to access Backbone models from Jasmine?

I think this is just a JavaScript scope question.
I'm trying to add some Jasmine tests to a Backbone application, but I can't figure out how to access Backbone models from within my Jasmine setup.
This is my current application structure (main.js is my Backbone application):
index.html
js/
main.js
vendor/
backbone.js
jquery.min.js // etc
tests/
SpecRunner.html
spec/
testSpec.js
The content of main.js is like this, and it's all running OK from index.html:
$(function(){
var Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
... etc
The files in SpecRunner.html look like this:
<!-- include source files here... -->
<script src="/js/vendor/jquery-1.10.2.min.js"></script>
<script src="/js/vendor/underscore.js"></script>
<script src="/js/vendor/backbone.js"></script>
<script src="/js/main.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/testSpec.js"></script>
I have written this test in testSpec.js, but it's failing with ReferenceError: Todo is not defined:
describe("Todo tests", function(){
var todo = new Todo("Get the milk", "Tuesday");
it("should be correctly defined", function(){
expect(todo).toBeDefined();
});
it("should have the correct title", function(){
expect(todo.title).toBe("Get the milk");
});
});
How can I get hold of the Todo scope? I've tried window.Todo but that doesn't help either.
As we can see at the Backbone reference.
constructor / initialize new Model([attributes], [options])
When creating an instance of a model, you can pass in the initial values of
the attributes, which will be set on the model.
The constructor needs to be initilized with a object literal(Key value pair), as follow:
new Book({
title: "One Thousand and One Nights",
author: "Scheherazade"
});
So you need to change your code to:
var todo = new Todo({
task: "Get the milk",
dayOfWeek: "Tuesday"
});
UPDATE:
Here you declared the Todo inside the jquery function scope and you're trying to access from outside.
$(function(){
var Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
etc...
}
}
You have two options, declare Todo as global, not recommend, but largely used at backbone samples:
$(function(){
window.Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
etc...
}
});
You could also try to call the jquery function after declaration:
$(function(){
var Todo = Backbone.Model.extend({
defaults: function() {
return {};
},
etc...
}
})();

backbone.js error as TypeError: this.on is not a function this.on("change:src", function(){

I have been going thru this book "developing backbone.js application"
where on page 18 theres a model function which goes like this:
(function($){
var Photo = Backbone.Model.extend({
defaults: {
'src': 'placeholder.jpg',
'title':'an image placeholder',
'coordinates':[0,0]
},
initialize:function(){
this.on("change:sr", function(){
var src = this.get("src");
console.log("Image src has been updated to: "+src);
});
},
changeSrc: function(source){
this.set({'src':source});
}
});
var somePhoto = new Photo({'src':'test.jpg', 'title':'testing'});
somPhoto.changeSrc('thatPhoto.jpg');
})(jQuery);
Its give me an error as
TypeError: this.on is not a function
this.on("change:src", function(){
on console.
Any Idea how i may solve this problem. I'm entirely new to Backbone.js.
Any Help is appreciated.
You might be using an old version of Backbone. on/off were only added on 0.9.0, before that they were called bind and unbind.
You should update to the latest Backbone (0.9.9 at the time of writing).

Categories